errors

package module
v0.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2020 License: MIT Imports: 6 Imported by: 45

README

errors gopher

Build Status codecov Go Report Card Maintainability

Errors

Errors package is a drop-in replacement of the built-in Go errors package with no external dependencies. It lets you create errors of 11 different types which should handle most of the use cases. Some of them are a bit too specific for web applications, but useful nonetheless. Following are the primary features of this package:

  1. Multiple (11) error types
  2. User friendly message
  3. File & line number prefixed to errors

In case of nested errors, the messages (in case of nesting with this package's error) & errors are also looped through.

Prerequisites

Go 1.13+

Available error types
  1. TypeInternal - is the error type for when there is an internal system error. e.g. Database errors
  2. TypeValidation - is the error type for when there is a validation error. e.g. invalid email address
  3. TypeInputBody - is the error type for when the input data is invalid. e.g. invalid JSON
  4. TypeDuplicate - is the error type for when there's duplicate content. e.g. user with email already exists (when trying to register a new user)
  5. TypeUnauthenticated - is the error type when trying to access an authenticated API without authentication
  6. TypeUnauthorized - is the error type for when there's an unauthorized access attempt
  7. TypeEmpty - is the error type for when an expected non-empty resource, is empty
  8. TypeNotFound - is the error type for an expected resource is not found. e.g. user ID not found
  9. TypeMaximumAttempts - is the error type for attempting the same action more than an allowed threshold
  10. TypeSubscriptionExpired - is the error type for when a user's 'paid' account has expired
  11. TypeDownstreamDependencyTimedout - is the error type for when a request to a downstream dependent service times out

Helper functions are available for all the error types. Each of them have 2 helper functions, one which accepts only a string, and the other which accepts an original error as well as a user friendly message.

All the dedicated error type functions are documented here. Names are consistent with the error type, e.g. errors.Internal(string) and errors.InternalErr(error, string)

User friendly messages

More often than not, when writing APIs, we'd want to respond with an easier to undersand user friendly message. Instead of returning the raw error. And log the raw error.

There are helper functions for all the error types, when in need of setting a friendly message, there are helper functions have a suffix 'Err'. All such helper functions accept the original error and a string.

package main
import(
    "fmt"
    "github.com/bnkamalesh/errors"
)

func Bar() error {
    return fmt.Errorf("hello %s", "world!")
}

func Foo() error {
    err := Bar()
    if err != nil {
        return errors.InternalErr(err, "bar is not happy")
    }
    return nil
}

func main() {
    err := Foo()
    fmt.Println(err)
    _,msg,_ := errors.HTTPStatusCodeMessage(err)
    fmt.Println(msg)
}
File & line number prefixed to errors

A common annoyance with Go errors which most people are aware of is, figuring out the origin of the error, especially when there are nested function calls. Ever since error annotation was introduced in Go, a lot of people have tried using it to trace out an errors origin by giving function names, contextual message etc in it. e.g. fmt.Errorf("database query returned error %w", err). This errors package, whenever you call the Go error interface's Error() string function, it'll print the error prefixed by the filepath and line number. It'd look like ../Users/JohnDoe/apps/main.go:50 hello world where 'hello world' is the error message.

How to use?

Before that, over the years I have tried error with stack trace, annotation, custom error package with error codes etc. Finally, I think this package gives the best of all worlds, for most generic usecases.

A sample was already shown in the user friendly message section, following one would show 1-2 scenarios.

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/bnkamalesh/errors"
	"github.com/bnkamalesh/webgo/v4"
	"github.com/bnkamalesh/webgo/v4/middleware"
)

func bar() error {
	return fmt.Errorf("%s %s", "sinking", "bar")
}

func bar2() error {
	err := bar()
	if err != nil {
		return errors.InternalErr(err, "bar2 was deceived by bar1 :(")
	}
	return nil
}

func foo() error {
	err := bar2()
	if err != nil {
		return errors.InternalErr(err, "we lost bar2!")
	}
	return nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	err := foo()
	if err != nil {
		// log the error on your server for troubleshooting
		fmt.Println(err.Error())
		// respond to request with friendly msg
		status, msg, _ := errors.HTTPStatusCodeMessage(err)
		webgo.SendError(w, msg, status)
		return
	}

	webgo.R200(w, "yay!")
}

func routes() []*webgo.Route {
	return []*webgo.Route{
		&webgo.Route{
			Name:    "home",
			Method:  http.MethodGet,
			Pattern: "/",
			Handlers: []http.HandlerFunc{
				handler,
			},
		},
	}
}

func main() {
	router := webgo.NewRouter(&webgo.Config{
		Host:         "",
		Port:         "8080",
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 60 * time.Second,
	}, routes())

	router.UseOnSpecialHandlers(middleware.AccessLog)
	router.Use(middleware.AccessLog)
	router.Start()
}

webgo was used to illustrate the usage of the function, errors.HTTPStatusCodeMessage. It returns the appropriate http status code, user friendly message stored within, and a boolean value. Boolean value is true if the returned error is of this package's error type. Since we get the status code and message separately, when using any web framework, you can set values according to the respective framework's native functions. In case of Webgo, it wraps errors in a struct of its own. Otherwise, you could directly respond to the HTTP request by calling errors.WriteHTTP(error,http.ResponseWriter).

Once the app is running, you can check the response by opening http://localhost:8080 on your browser. Or on terminal

$ curl http://localhost:8080
{"errors":"we lost bar2!. bar2 was deceived by bar1 :(","status":500} // HTTP response

And output of the fmt.Println(err.Error())

/Users/username/go/src/errorscheck/main.go:28 /Users/username/go/src/errorscheck/main.go:20 sinking bar

Contributing

If more error types, customization etc. are required, PRs & issues are welcome!

The gopher

The gopher used here was created using Gopherize.me. Show some love to Go errors like our gopher lady here!

Documentation

Overview

Package errors helps in wrapping errors with custom type as well as a user friendly message. This is particularly useful when responding to APIs

Index

Constants

View Source
const (
	// TypeInternal is error type for when there is an internal system error. e.g. Database errors
	TypeInternal errType = iota
	// TypeValidation is error type for when there is a validation error. e.g. invalid email address
	TypeValidation
	// TypeInputBody is error type for when an input data type error. e.g. invalid JSON
	TypeInputBody
	// TypeDuplicate is error type for when there's duplicate content
	TypeDuplicate
	// TypeUnauthenticated is error type when trying to access an authenticated API without authentication
	TypeUnauthenticated
	// TypeUnauthorized is error type for when there's an unauthorized access attempt
	TypeUnauthorized
	// TypeEmpty is error type for when an expected non-empty resource, is empty
	TypeEmpty
	// TypeNotFound is error type for an expected resource is not found e.g. user ID not found
	TypeNotFound
	// TypeMaximumAttempts is error type for attempting the same action more than allowed
	TypeMaximumAttempts
	// TypeSubscriptionExpired is error type for when a user's 'paid' account has expired
	TypeSubscriptionExpired
	// TypeDownstreamDependencyTimedout is error type for when a request to a downstream dependent service times out
	TypeDownstreamDependencyTimedout

	// DefaultMessage is the default user friendly message
	DefaultMessage = "unknown error occurred"
)

While adding a new Type, the respective helper functions should be added, also update the WriteHTTP method accordingly

Variables

This section is empty.

Functions

func As

func As(err error, target interface{}) bool

As calls the Go builtin errors.As

func HTTPStatusCodeMessage

func HTTPStatusCodeMessage(err error) (int, string, bool)

HTTPStatusCodeMessage returns the appropriate HTTP status code, message, boolean for the error the boolean value is true if the error was of type *Error, false otherwise

func Is

func Is(err, target error) bool

Is calls the Go builtin errors.Is

func SetDefaultType

func SetDefaultType(e errType)

SetDefaultType will set the default error type, which is used in the 'New' function

func Unwrap

func Unwrap(err error) error

Unwrap calls the Go builtin errors.UnUnwrap

func WriteHTTP

func WriteHTTP(err error, w http.ResponseWriter)

WriteHTTP is a convenience method which will check if the error is of type *Error and respond appropriately

Types

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error is the struct which holds custom attributes

func DownstreamDependencyTimedout

func DownstreamDependencyTimedout(message string) *Error

DownstreamDependencyTimedout is a helper function to create a new error of type TypeDownstreamDependencyTimedout

func DownstreamDependencyTimedoutErr

func DownstreamDependencyTimedoutErr(original error, message string) *Error

DownstreamDependencyTimedoutErr is a helper function to create a new error of type TypeDownstreamDependencyTimedout which also accepts an original error

func Duplicate

func Duplicate(message string) *Error

Duplicate is a helper function to create a new error of type TypeDuplicate

func DuplicateErr

func DuplicateErr(original error, message string) *Error

DuplicateErr is a helper function to create a new error of type TypeDuplicate which also accepts an original error

func Empty

func Empty(message string) *Error

Empty is a helper function to create a new error of type TypeEmpty

func EmptyErr

func EmptyErr(original error, message string) *Error

EmptyErr is a helper function to create a new error of type TypeEmpty which also accepts an original error

func InputBody

func InputBody(message string) *Error

InputBody is a helper function to create a new error of type TypeInputBody

func InputBodyErr

func InputBodyErr(original error, message string) *Error

InputBodyErr is a helper function to create a new error of type TypeInputBody which also accepts an original error

func Internal added in v0.1.7

func Internal(message string) *Error

Internal helper method for creation internal errors

func InternalErr

func InternalErr(original error, message string) *Error

InternalErr helper method for creation internal errors which also accepts an original error

func MaximumAttempts

func MaximumAttempts(message string) *Error

MaximumAttempts is a helper function to create a new error of type TypeMaximumAttempts

func MaximumAttemptsErr

func MaximumAttemptsErr(original error, message string) *Error

MaximumAttemptsErr is a helper function to create a new error of type TypeMaximumAttempts which also accepts an original error

func New

func New(msg string) *Error

New returns a new instance of Error with the relavant fields initialized

func NewWithErrMsgType

func NewWithErrMsgType(e error, message string, etype errType) *Error

NewWithErrMsgType returns an error instance with custom error type and message

func NewWithType

func NewWithType(msg string, etype errType) *Error

NewWithType returns an error instance with custom error type

func NotFound

func NotFound(message string) *Error

NotFound is a helper function to create a new error of type TypeNotFound

func NotFoundErr

func NotFoundErr(original error, message string) *Error

NotFoundErr is a helper function to create a new error of type TypeNotFound which also accepts an original error

func SubscriptionExpired

func SubscriptionExpired(message string) *Error

SubscriptionExpired is a helper function to create a new error of type TypeSubscriptionExpired

func SubscriptionExpiredErr

func SubscriptionExpiredErr(original error, message string) *Error

SubscriptionExpiredErr is a helper function to create a new error of type TypeSubscriptionExpired which also accepts an original error

func Unauthenticated

func Unauthenticated(message string) *Error

Unauthenticated is a helper function to create a new error of type TypeUnauthenticated

func UnauthenticatedErr

func UnauthenticatedErr(original error, message string) *Error

UnauthenticatedErr is a helper function to create a new error of type TypeUnauthenticated which also accepts an original error

func Unauthorized

func Unauthorized(message string) *Error

Unauthorized is a helper function to create a new error of type TypeUnauthorized

func UnauthorizedErr

func UnauthorizedErr(original error, message string) *Error

UnauthorizedErr is a helper function to create a new error of type TypeUnauthorized which also accepts an original error

func Validation

func Validation(message string) *Error

Validation is a helper function to create a new error of type TypeValidation

func ValidationErr

func ValidationErr(original error, message string) *Error

ValidationErr helper method for creation validation errors which also accepts an original error

func (*Error) Error

func (e *Error) Error() string

Error is the implementation of error interface

func (*Error) HTTPStatusCode

func (e *Error) HTTPStatusCode() int

HTTPStatusCode is a convenience method used to get the appropriate HTTP response status code for the respective error type

func (*Error) Is added in v0.1.6

func (e *Error) Is(err error) bool

Is implements the Is interface required by Go

func (*Error) Message

func (e *Error) Message() string

Message returns the user friendly message stored in the error struct

func (*Error) Type

func (e *Error) Type() errType

Type returns the error type as integer

func (*Error) Unwrap added in v0.1.6

func (e *Error) Unwrap() error

Unwrap implement's Go 1.13's Unwrap interface exposing the wrapped error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL