One place for hosting & domains

      Handling

      Handling Authentication In Vue Using Vuex


      Introduction

      Traditionally, many people use local storage to manage tokens generated through client-side authentication. A big concern is always a better way to manage authorization tokens to allow us to store even more information on users.

      This is where Vuex comes in. Vuex manages states for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.

      Sounds like a better alternative to always checking localStorage? Let’s explore it.

      Prerequisites

      1. Node installed on your local system
      2. Knowledge of JavaScript and Vue
      3. Install Vue CLI on your local system.
      4. Read through Vue Authentication And Route Handling Using Vue-router

      If you want to jump straight to the demo code: Go to vue-auth-vuex on GitHub

      Setting up the application modules

      For this project, we want to create a vue application that has vuex and vue-router. We will use the vue cli 3.0 to create a new vue project and select router and vuex from the options.

      Run the following command to set it up:

      $ vue create vue-auth
      

      Follow the dialogue that shows up, add the necessary information and select the options we need and complete the installation.

      Next, install axios:

      $ npm install axios --save
      

      Setup Axios

      We will need axios across many of our components. Let’s set it up at the entry level so we do not have to import it every time we need it.

      Open the ./src/main.js file and add the following:

      [...]
      import store from './store'
      import Axios from 'axios'
      
      Vue.prototype.$http = Axios;
      const token = localStorage.getItem('token')
      if (token) {
        Vue.prototype.$http.defaults.headers.common['Authorization'] = token
      }
      [...]
      

      Now, when we want to use axios inside our component, we can do this.$http and it will be like calling axios directly. We also set the Authorization on axios header to our token, so our requests can be processed if a token is required. This way, we do not have to set token anytime we want to make a request.

      When that is done, let’s set up the server to handle authentication.

      Setting up the server for authentication

      I already wrote about this when explaining how to handle authentication with vue-router. Check out the Setup Node.js Server section of this

      Setup Components

      The Login Component

      Create a file Login.vue in the ./src/components directory. Then, add the template for the login page:

      <template>
       <div>
         <form class="login" @submit.prevent="login">
           <h1>Sign in</h1>
           <label>Email</label>
           <input required v-model="email" type="email" placeholder="Name"/>
           <label>Password</label>
           <input required v-model="password" type="password" placeholder="Password"/>
           <hr/>
           <button type="submit">Login</button>
         </form>
       </div>
      </template>
      

      When you are done, add the data attributes that would bind to the HTML form:

      [...]
      <script>
        export default {
          data(){
            return {
              email : "",
              password : ""
            }
          },
        }
      </script>
      

      Now, let’s add the method for handling login:

      [...]
      <script>
        export default {
          [...]
          methods: {
            login: function () {
              let email = this.email 
              let password = this.password
              this.$store.dispatch('login', { email, password })
             .then(() => this.$router.push('/'))
             .catch(err => console.log(err))
            }
          }
        }
      </script>
      

      We are using a vuex action — login to handle this authentication. We can resolve actions into promises so we can do cool things with them inside our component.

      The Register Component

      Like the component for login, let’s make one for registering users. Start by creating a file Register.vue in the components directory and add the following to it:

      <template>
        <div>
          <h4>Register</h4>
          <form @submit.prevent="register">
            <label for="name">Name</label>
            <div>
                <input id="name" type="text" v-model="name" required autofocus>
            </div>
      
            <label for="email" >E-Mail Address</label>
            <div>
                <input id="email" type="email" v-model="email" required>
            </div>
      
            <label for="password">Password</label>
            <div>
                <input id="password" type="password" v-model="password" required>
            </div>
      
            <label for="password-confirm">Confirm Password</label>
            <div>
                <input id="password-confirm" type="password" v-model="password_confirmation" required>
            </div>
      
            <div>
                <button type="submit">Register</button>
            </div>
          </form>
        </div>
      </template>
      

      Let define the data attributes we will bind to the form:

      [...]
      <script>
        export default {
          data(){
            return {
              name : "",
              email : "",
              password : "",
              password_confirmation : "",
              is_admin : null
            }
          },
        }
      </script>
      

      Now, let’s add the method for handling login:

      [...]
      <script>
        export default {
          [...]
          methods: {
            register: function () {
              let data = {
                name: this.name,
                email: this.email,
                password: this.password,
                is_admin: this.is_admin
              }
              this.$store.dispatch('register', data)
             .then(() => this.$router.push('/'))
             .catch(err => console.log(err))
            }
          }
        }
      </script>
      

      The Secure Component

      Let’s make a simple component that would only display if our user is authenticated. Create the component file Secure.vue and add the following to it:

      <template>
        <div>
          <h1>This page is protected by auth</h1>
        </div>
      </template>
      

      Update The App Component

      Open ./src/App.vue file and add the following to it:

      <template>
        <div id="app">
          <div id="nav">
            <router-link to="/">Home</router-link> |
            <router-link to="/about">About</router-link><span v-if="isLoggedIn"> | <a @click="logout">Logout</a></span>
          </div>
          <router-view/>
        </div>
      </template>
      

      Can you see the Logout link we set to only show up if a user is logged in? Great.

      Now, let’s add the logic behind the log out:

      <script>
        export default {
          computed : {
            isLoggedIn : function(){ return this.$store.getters.isLoggedIn}
          },
          methods: {
            logout: function () {
              this.$store.dispatch('logout')
              .then(() => {
                this.$router.push('/login')
              })
            }
          },
        }
      </script>
      

      We are doing two things — computing the authentication state of the user and dispatching a logout action to our vuex store when a user clicks the logout button. After the log out, we send the user to login page using this.$router.push('/login'). You can change where the user gets sent to if you want.

      That’s it. Let’s make the auth module using vuex.

      Vuex Auth Module

      If you read past the Setup Node.js Server section, you would notice we had to store user auth token in localStorage and we had to retrieve both the token and user information anytime we wanted to check if the user is authenticated. This works, but it is not really elegant. We will rebuild the authentication to use vuex.

      First, let’s setup our store.js file for vuex:

      import Vue from 'vue'
      import Vuex from 'vuex'
      import axios from 'axios'
      
      Vue.use(Vuex)
      
      export default new Vuex.Store({
        state: {
          status: '',
          token: localStorage.getItem('token') || '',
          user : {}
        },
        mutations: {
      
        },
        actions: {
      
        },
        getters : {
      
        }
      })
      

      If you noticed, we have imported vue, vuex and axios, then asked vue to use vuex. This is because we mean serious business here.

      We have defined the attributes of the state. Now the vuex state would hold our authentication status, jwt token and user information.

      Create The Vuex login Action

      Vuex actions are used to commit mutations to the vuex store. We will create a login action that would authenticate a user with the server and commit user credentials to the vuex store. Open the ./src/store.js file and add the following to actions object:

      login({commit}, user){
          return new Promise((resolve, reject) => {
            commit('auth_request')
            axios({url: 'http://localhost:3000/login', data: user, method: 'POST' })
            .then(resp => {
              const token = resp.data.token
              const user = resp.data.user
              localStorage.setItem('token', token)
              axios.defaults.headers.common['Authorization'] = token
              commit('auth_success', token, user)
              resolve(resp)
            })
            .catch(err => {
              commit('auth_error')
              localStorage.removeItem('token')
              reject(err)
            })
          })
      },
      

      The login action passes vuex commit helper that we will use to trigger mutations. Mutations make changes to vuex store.

      We are making a call to the server’s login route and returning the necessary data. We store the token on localStorage, then pass the token and user information to auth_success to update the store’s attributes. We also set the header for axios at this point as well.

      We could store the token in vuex store, but if the user leaves our application, all of the data in the vuex store disappears. To ensure we allow the user to return to the application within the validity time of the token and not have to log in again, we have to keep the token in localStorage.

      It’s important you know how these work so you can decide what exactly it is you want to achieve.

      We return a promise so we can return a response to a user after login is complete.

      Create The Vuex register Action

      Like the login action, the register action will work almost the same way. In the same file, add the following in the actions object:

      register({commit}, user){
        return new Promise((resolve, reject) => {
          commit('auth_request')
          axios({url: 'http://localhost:3000/register', data: user, method: 'POST' })
          .then(resp => {
            const token = resp.data.token
            const user = resp.data.user
            localStorage.setItem('token', token)
            axios.defaults.headers.common['Authorization'] = token
            commit('auth_success', token, user)
            resolve(resp)
          })
          .catch(err => {
            commit('auth_error', err)
            localStorage.removeItem('token')
            reject(err)
          })
        })
      },
      

      This works similarly to login action, calling the same mutators as our login and register actions have the same simple goal — get a user into the system.

      Create The Vuex logout Action

      We want the user to have the ability to log out of the system, and we want to destroy all data created during the last authenticated session. In the same actions object, add the following:

      logout({commit}){
        return new Promise((resolve, reject) => {
          commit('logout')
          localStorage.removeItem('token')
          delete axios.defaults.headers.common['Authorization']
          resolve()
        })
      }
      

      Now, when the user clicks to log out, we will remove the jwt token we stored along with the axios header we set. There is no way they can perform a transaction requiring a token now.

      Create The Mutations

      Like I mentioned earlier, mutators are used to change the state of a vuex store. Let’s define the mutators we had used throughout our application. In the mutators object, add the following:

      mutations: {
        auth_request(state){
          state.status="loading"
        },
        auth_success(state, token, user){
          state.status="success"
          state.token = token
          state.user = user
        },
        auth_error(state){
          state.status="error"
        },
        logout(state){
          state.status=""
          state.token = ''
        },
      },
      

      Create The Getters

      We use getter to get the value of the attributes of vuex state. The role of our getter in the situation is to separate application data from application logic and ensure we do not give away sensitive information.

      Add the following to the getters object:

      getters : {
        isLoggedIn: state => !!state.token,
        authStatus: state => state.status,
      }
      

      You would agree with me that this is a neater way to access data in the store.

      Hide Pages Behind Auth

      The whole purpose of this article is to implement authentication and keep certain pages away from a user who is not authentication. To achieve this, we need to know the page the user wants to visit and equally have a way to check if the user is authenticated. We also need a way to say if the page is reserved for only authenticated user or unauthenticated user alone or both. These things are important considerations which, luckily, we can achieve with vue-router.

      Defiing Routes For Authenticated And Unauthenticated Pages

      Open the ./src/router.js file and import what we need for this setup:

      import Vue from 'vue'
      import Router from 'vue-router'
      import store from './store.js'
      import Home from './views/Home.vue'
      import About from './views/About.vue'
      import Login from './components/Login.vue'
      import Secure from './components/Secure.vue'
      import Register from './components/Register.vue'
      
      Vue.use(Router)
      

      As you can see, we have imported vue, vue-router and our vuex store setup. We also imported all the components we defined and set vue to use our router.

      Let’s define the routes:

      [...]
      let router = new Router({
        mode: 'history',
        routes: [
          {
            path: '/',
            name: 'home',
            component: Home
          },
          {
            path: '/login',
            name: 'login',
            component: Login
          },
          {
            path: '/register',
            name: 'register',
            component: Register
          },
          {
            path: '/secure',
            name: 'secure',
            component: Secure,
            meta: { 
              requiresAuth: true
            }
          },
          {
            path: '/about',
            name: 'about',
            component: About
          }
        ]
      })
      
      export default router
      

      Our route definition is simple. For routes requiring authentication, we add extra data to it to enable us identify it when the user tries to access it. This is the essence of the meta attribute added to the route definition. If you are asking ”Can I add more data to this meta and use it?” then I’m pleased to tell you that you are absolutely right ?.

      Handling Unauthorized Access Cases

      We have our routes defined. Now, let’s check for unauthorized access and take action.
      In the router.js file, add the following before the export default router:

      router.beforeEach((to, from, next) => {
        if(to.matched.some(record => record.meta.requiresAuth)) {
          if (store.getters.isLoggedIn) {
            next()
            return
          }
          next('/login') 
        } else {
          next() 
        }
      })
      

      From the article on using vue router for authentication, you can recall we had a really complex mechanism here that grew very big and got very confusing. Vuex has helped us simplify that completely, and we can go on to add any condition to our route. In our vuex store, we can then define actions to check these conditions and getters to return them.

      Handling Expired Token Cases

      Because we store our token in localStorage, it can remain there perpetually. This means that whenever we open our application, it would automatically authenticate a user even if the token has expired. What would happen at most is that our requests would keep failing because of an invalid token. This is bad for user experience.

      Now, open ./src/App.vue file and in the script, add the following to it:

      export default {
        [...]
        created: function () {
          this.$http.interceptors.response.use(undefined, function (err) {
            return new Promise(function (resolve, reject) {
              if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
                this.$store.dispatch(logout)
              }
              throw err;
            });
          });
        }
      }
      

      We are intercepting axios call to determine if we get 401 Unauthorized response. If we do, we dispatch the logout action and the user gets logged out of the application. This takes them to the login page like we designed earlier and they can log in again.

      We can agree that this will greatly improve the user’s experience.

      Conclusion

      Using vuex allows us to store and manage authentication state and proceed to check state in our application using only a few lines of code.



      Source link

      Handling CRUD in Laravel With Eloquent ORM


      This Tech Talk is free and open to everyone. Register on Eventbrite here to receive a link to join on Thursday, September 17, 2020, 1:00–2:00 p.m. ET.

      About the Talk

      Laravel helps us to handle database operations. Eloquent ORM lets us avoid writing SQL statements out by hand.

      What You’ll Learn

      • How to use Eloquent ORM to perform CRUD (create, read, update, and delete)
      • How to generate relationships
      • How to manage your database with migrations

      This Talk is Designed For

      Laravel developers that want to build any applications or sites.

      Technical Level

      Beginner. You have basic knowledge of Laravel and want to make CRUD easy.

      About the Presenter

      Chris Sevilleja (@chrisoncode) is the founder of scotch.io and Senior Developer Advocate at DigitalOcean. He loves trying to figure out the most efficient and practical way to build apps that we can ship to our customers.

      How to Join

      To join the live Tech Talk, register here.



      Source link

      Handling Panics in Go


      Introduction

      Errors that a program encounters fall into two broad categories: those the programmer has anticipated and those the programmer has not. The error interface that we have covered in our previous two articles on error handling largely deal with errors that we expect as we are writing Go programs. The error interface even allows us to acknowledge the rare possibility of an error occurring from function calls, so we can respond appropriately in those situations.

      Panics fall into the second category of errors, which are unanticipated by the programmer. These unforeseen errors lead a program to spontaneously terminate and exit the running Go program. Common mistakes are often responsible for creating panics. In this tutorial, we’ll examine a few ways that common operations can produce panics in Go, and we’ll also see ways to avoid those panics. We’ll also use defer statements along with the recover function to capture panics before they have a chance to unexpectedly terminate our running Go programs.

      Understanding Panics

      There are certain operations in Go that automatically return panics and stop the program. Common operations include indexing an array beyond its capacity, performing type assertions, calling methods on nil pointers, incorrectly using mutexes, and attempting to work with closed channels. Most of these situations result from mistakes made while programming that the compiler has no ability to detect while compiling your program.

      Since panics include detail that is useful for resolving an issue, developers commonly use panics as an indication that they have made a mistake during a program’s development.

      Out of Bounds Panics

      When you attempt to access an index beyond the length of a slice or the capacity of an array, the Go runtime will generate a panic.

      The following example makes the common mistake of attempting to access the last element of a slice using the length of the slice returned by the len builtin. Try running this code to see why this might produce a panic:

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          names := []string{
              "lobster",
              "sea urchin",
              "sea cucumber",
          }
          fmt.Println("My favorite sea creature is:", names[len(names)])
      }
      

      This will have the following output:

      Output

      panic: runtime error: index out of range [3] with length 3 goroutine 1 [running]: main.main() /tmp/sandbox879828148/prog.go:13 +0x20

      The name of the panic’s output provides a hint: panic: runtime error: index out of range. We created a slice with three sea creatures. We then tried to get the last element of the slice by indexing that slice with the length of the slice using the len builtin function. Remember that slices and arrays are zero-based; so the first element is zero and the last element in this slice is at index 2. Since we try to access the slice at the third index, 3, there is no element in the slice to return because it is beyond the bounds of the slice. The runtime has no option but to terminate and exit since we have asked it to do something impossible. Go also can’t prove during compilation that this code will try to do this, so the compiler cannot catch this.

      Notice also that the subsequent code did not run. This is because a panic is an event that completely halts the execution of your Go program. The message produced contains multiple pieces of information helpful for diagnosing the cause of the panic.

      Anatomy of a Panic

      Panics are composed of a message indicating the cause of the panic and a stack trace that helps you locate where in your code the panic was produced.

      The first part of any panic is the message. It will always begin with the string panic:, which will be followed with a string that varies depending on the cause of the panic. The panic from the previous exercise has the message:

      panic: runtime error: index out of range [3] with length 3
      

      The string runtime error: following the panic: prefix tells us that the panic was generated by the language runtime. This panic is telling us that we attempted to use an index [3] that was out of range of the slice’s length 3.

      Following this message is the stack trace. Stack traces form a map that we can follow to locate exactly what line of code was executing when the panic was generated, and how that code was invoked by earlier code.

      goroutine 1 [running]:
      main.main()
          /tmp/sandbox879828148/prog.go:13 +0x20
      

      This stack trace, from the previous example, shows that our program generated the panic from the file /tmp/sandbox879828148/prog.go at line number 13. It also tells us that this panic was generated in the main() function from the main package.

      The stack trace is broken into separate blocks—one for each goroutine in your program. Every Go program’s execution is accomplished by one or more goroutines that can each independently and simultaneously execute parts of your Go code. Each block begins with the header goroutine X [state]:. The header gives the ID number of the goroutine along with the state that it was in when the panic occurred. After the header, the stack trace shows the function that the program was executing when the panic happened, along with the filename and line number where the function executed.

      The panic in the previous example was generated by an out-of-bounds access to a slice. Panics can also be generated when methods are called on pointers that are unset.

      Nil Receivers

      The Go programming language has pointers to refer to a specific instance of some type existing in the computer’s memory at runtime. Pointers can assume the value nil indicating that they are not pointing at anything. When we attempt to call methods on a pointer that is nil, the Go runtime will generate a panic. Similarly, variables that are interface types will also produce panics when methods are called on them. To see the panics generated in these cases, try the following example:

      package main
      
      import (
          "fmt"
      )
      
      type Shark struct {
          Name string
      }
      
      func (s *Shark) SayHello() {
          fmt.Println("Hi! My name is", s.Name)
      }
      
      func main() {
          s := &Shark{"Sammy"}
          s = nil
          s.SayHello()
      }
      

      The panics produced will look like this:

      Output

      panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xdfeba] goroutine 1 [running]: main.(*Shark).SayHello(...) /tmp/sandbox160713813/prog.go:12 main.main() /tmp/sandbox160713813/prog.go:18 +0x1a

      In this example, we defined a struct called Shark. Shark has one method defined on its pointer receiver called SayHello that will print a greeting to standard out when called. Within the body of our main function, we create a new instance of this Shark struct and request a pointer to it using the & operator. This pointer is assigned to the s variable. We then reassign the s variable to the value nil with the statement s = nil. Finally we attempt to call the SayHello method on the variable s. Instead of receiving a friendly message from Sammy, we receive a panic that we have attempted to access an invalid memory address—this is because we set the s variable to nil.

      While we have set s to nil explicitly in this example, in practice this happens less obviously. When you see panics involving nil pointer dereference, be sure that you have properly assigned any pointer variables that you may have created.

      Panics generated from nil pointers and out-of-bounds accesses are two commonly occurring panics generated by the runtime. It is also possible to manually generate a panic using a builtin function.

      Using the panic Builtin Function

      We can also generate panics of our own using the panic built-in function. It takes a single string as an argument, which is the message the panic will produce. Typically this message is less verbose than rewriting our code to return an error. Furthermore, we can use this within our own packages to indicate to developers that they may have made a mistake when using our package’s code. Whenever possible, best practice is to try to return error values to consumers of our package.

      Run this code to see a panic generated from a function called from another function:

      package main
      
      func main() {
          foo()
      }
      
      func foo() {
          panic("oh no!")
      }
      

      The panic output produced looks like:

      Output

      panic: oh no! goroutine 1 [running]: main.foo(...) /tmp/sandbox494710869/prog.go:8 main.main() /tmp/sandbox494710869/prog.go:4 +0x40

      Here we define a function foo that calls the panic builtin with the string "oh no!". This function is called by our main function. Notice how the output has the message panic: oh no! and the stack trace shows a single goroutine with two lines in the stack trace: one for the main() function and one for our foo() function.

      We’ve seen that panics appear to terminate our program where they are generated. This can create problems when there are open resources that need to be properly closed. Go provides a mechanism to execute some code always, even in the presence of a panic.

      Deferred Functions

      Your program may have resources that it must clean up properly, even while a panic is being processed by the runtime. Go allows you to defer the execution of a function call until its calling function has completed execution. Deferred functions run even in the presence of a panic, and are used as a safety mechanism to guard against the chaotic nature of panics. Functions are deferred by calling them as usual, then prefixing the entire statement with the defer keyword, as in defer sayHello(). Run this example to see how a message can be printed even though a panic was produced:

      package main
      
      import "fmt"
      
      func main() {
          defer func() {
              fmt.Println("hello from the deferred function!")
          }()
      
          panic("oh no!")
      }
      

      The output produced from this example will look like:

      Output

      hello from the deferred function! panic: oh no! goroutine 1 [running]: main.main() /Users/gopherguides/learn/src/github.com/gopherguides/learn//handle-panics/src/main.go:10 +0x55

      Within the main function of this example, we first defer a call to an anonymous function that prints the message "hello from the deferred function!". The main function then immediately produces a panic using the panic function. In the output from this program, we first see that the deferred function is executed and prints its message. Following this is the panic we generated in main.

      Deferred functions provide protection against the surprising nature of panics. Within deferred functions, Go also provides us the opportunity to stop a panic from terminating our Go program using another built-in function.

      Handling Panics

      Panics have a single recovery mechanism—the recover builtin function. This function allows you to intercept a panic on its way up through the call stack and prevent it from unexpectedly terminating your program. It has strict rules for its use, but can be invaluable in a production application.

      Since it is part of the builtin package, recover can be called without importing any additional packages:

      package main
      
      import (
          "fmt"
          "log"
      )
      
      func main() {
          divideByZero()
          fmt.Println("we survived dividing by zero!")
      
      }
      
      func divideByZero() {
          defer func() {
              if err := recover(); err != nil {
                  log.Println("panic occurred:", err)
              }
          }()
          fmt.Println(divide(1, 0))
      }
      
      func divide(a, b int) int {
          return a / b
      }
      

      This example will output:

      Output

      2009/11/10 23:00:00 panic occurred: runtime error: integer divide by zero we survived dividing by zero!

      Our main function in this example calls a function we define, divideByZero. Within this function, we defer a call to an anonymous function responsible for dealing with any panics that may arise while executing divideByZero. Within this deferred anonymous function, we call the recover builtin function and assign the error it returns to a variable. If divideByZero is panicking, this error value will be set, otherwise it will be nil. By comparing the err variable against nil, we can detect if a panic occurred, and in this case we log the panic using the log.Println function, as though it were any other error.

      Following this deferred anonymous function, we call another function that we defined, divide, and attempt to print its results using fmt.Println. The arguments provided will cause divide to perform a division by zero, which will produce a panic.

      In the output to this example, we first see the log message from the anonymous function that recovers the panic, followed by the message we survived dividing by zero!. We have indeed done this, thanks to the recover builtin function stopping an otherwise catastrophic panic that would terminate our Go program.

      The err value returned from recover() is exactly the value that was provided to the call to panic(). It’s therefore critical to ensure that the err value is only nil when a panic has not occurred.

      Detecting Panics with recover

      The recover function relies on the value of the error to make determinations as to whether a panic occurred or not. Since the argument to the panic function is an empty interface, it can be any type. The zero value for any interface type, including the empty interface, is nil. Care must be taken to avoid nil as an argument to panic as demonstrated by this example:

      package main
      
      import (
          "fmt"
          "log"
      )
      
      func main() {
          divideByZero()
          fmt.Println("we survived dividing by zero!")
      
      }
      
      func divideByZero() {
          defer func() {
              if err := recover(); err != nil {
                  log.Println("panic occurred:", err)
              }
          }()
          fmt.Println(divide(1, 0))
      }
      
      func divide(a, b int) int {
          if b == 0 {
              panic(nil)
          }
          return a / b
      }
      
      

      This will output:

      Output

      we survived dividing by zero!

      This example is the same as the previous example involving recover with some slight modifications. The divide function has been altered to check if its divisor, b, is equal to 0. If it is, it will generate a panic using the panic builtin with an argument of nil. The output, this time, does not include the log message showing that a panic occurred even though one was created by divide. This silent behavior is why it is very important to ensure that the argument to the panic builtin function is not nil.

      Conclusion

      We have seen a number of ways that panics can be created in Go and how they can be recovered from using the recover builtin. While you may not necessarily use panic yourself, proper recovery from panics is an important step of making Go applications production-ready.

      You can also explore our entire How To Code in Go series.



      Source link