errors handling in GO!
Tags: go, errors, stacktrace
Published: 2020-06-27 13:42:05



Today many programmers find it difficult to handle errors resulting from code bugs or by notification by the user, the developers are responsible for  these errors for not noticing, in this series I will explain methods of handling errors in  Golang .Go errors are implemented in the Error interface and must be handled in every layer of code. Go errors don't work like exceptions, and unhandled errors can cause massive problems. You should seek to deal with errors and consider them when they occur.

## The Error interface

The error type is a simple  interface type :

```go

type Error interface{
  Error() string
}
```

to create error value in package level that you can check ,you can use 
<code>error.New()</code> implemented in <code>errors</code>package

```go
// ErrorNotValidURL is a description of a not valid URL
var ErrorNotValidURL = errors.New("given text is not url")

// we check errors value

if err == urlextractor.ErrorNotValidURL {
  fmt.Println("not a valid url ")
 }
```

to make an error type, you declare new <code>struct</code> with error's name

```go
// NotValidURLError is a description of a malformed URL
type NotValidURLError struct {
 error
}
// We check the type of the error

 switch _, err := urlextractor.IsURL("not URL !"); err.(type) {
 case nil:
  fmt.Println("No Error returned")
 case urlextractor.NotValidURLError:
  fmt.Println("Type1 Error: ", err)

 }

```

a flexible way to implement custom error is as a struct that will implement the <code>error()</code> interface that you can put extra functions
to add more pieces of information on the error type

```go

// NotValidURLError is a struct that will implement
// the Error() interface
type NotValidURLError struct {
 Source string
}

func (c NotValidURLError) Error() string {
 return fmt.Sprintf("%s is not valid URL", c.Source)
}

```

the only requirement to use <code>Error()</code> interface only returns a valid string, you can combine this with a structure to provide a consistent error handling throughout

## Wrapping errors

when you implement a new library that contains complex manipulation you need to ensure to keep traces of context in errors by prefixing them or printing the full stack trace,to annotate an error in such manner, the <code>github.com/pkg/errors</code> package has the following function

```go
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error
```

the <code>wrap</code> function  takes an error, and a message and produces a new error

```go
// URLExtractorError demonstrates error wrapping and
// annotating an error
func URLExtractorError(e error) error {
 return errors.Wrap(e, "An error occurred in URLExtractor")
}
func IsURL(url string) (bool, error) {
 re := regexp.MustCompile(`^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$`)
 result := re.Find([]byte(url))
 if len(result) == 0 {
  return false, URLExtractorError(NotValidURLError{errors.New("malformed URL :" + url)})
 }

 return true, nil

}
```

We’ll use this function from the main

```go
func main() {
 _, err := urlextractor.IsURL("not URL !")

 if err != nil {
  fmt.Println(err)
 }
}

```

when <code>IsURL</code> fail, we get the annotated error

```sh
An error occurred in URLExtractor: malformed URL: not URL!
```

to inspect the stack trace we can do more by replacing <code>fmt.Println(err)</code> with <code>fmt.Printf("%+v\n", err)</code>

```sh
go-err/urlextractor.URLExtractorError
        /home/abdelhak/LP/go-err/urlextractor/urlextract.go:20
go-err/urlextractor.IsURL
        /home/abdelhak/LP/go-err/urlextractor/urlextract.go:38
```