errors

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: May 22, 2021 License: MIT Imports: 6 Imported by: 41

README

Go Report Card

errors

Builds on Go 1.13 errors by adding HTTP statuses and GRPC codes to them.

Installation

go get -u github.com/stackus/errors

Prerequisites

Go 1.13

Adding HTTP status and GRPC codes to your errors

The errors.Wrap(error, string) error function is used to embed an errors.Error or to wrap other errors. When used with an errors.Error the desired message is not altered. Wrapping other errors will prefix the message before the wrapped error message.

err := errors.Wrap(errors.ErrNotFound, "found nothing")
fmt.Println(err) // Outputs: "found nothing"
err = errors.Wrap(err, "a prefixed message")
fmt.Println(err) // Outputs: "a prefixed message: found nothing"

HTTP Statuses

The wrapped errors.Error can be checked with errors.As() and the errors.HTTPCoder interface to locate the HTTP status.

err := errors.Wrap(errors.ErrNotFound, "found nothing")
var coder errors.HTTPCoder
if errors.As(err, &coder) {
    fmt.Println(coder.HTTPCode()) // Outputs: 404
}

GRPC Codes

A similar method can be used to get the GRPC codes with the errors.GRPCCoder interface.

err := errors.Wrap(errors.NotFound, "found nothing")
var coder errors.GRPCCoder
if errors.As(err, &coder) {
    fmt.Println(coder.GRPCCode()) // Outputs: 5

Transmitting errors with GRPC

The methods SendGRPCError(error) error and ReceiveGRPCError(error) error provide a way to convert a status.Status and its error into an errors.Error and vice versa. You can use these in your server and client handlers directly, or they can be used with GRPC interceptors.

Server Example:

func serverErrorUnaryInterceptor() grpc.UnaryServerInterceptor {
    return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	    return resp, errors.SendGRPCError(err)
	}
}

server := grpc.NewServer(grpc.ChainUnaryInterceptor(serverErrorUnaryInterceptor()))

Client Example:

func clientErrorUnaryInterceptor() grpc.UnaryClientInterceptor {
    return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	    return errors.ReceiveGRPCError(invoker(ctx, method, req, reply, cc, opts...))
	}
}

cc, err := grpc.Dial(uri, grpc.WithChainUnaryInterceptor(clientErrorUnaryInterceptor()))

There is no requirement that both the server and client use this library to benefit from coded errors.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT

Documentation

Overview

Package errors builds on Go 1.13 errors adding HTTP and GRPC code to your errors.

Wrap() and Wrapf()

When the wrap functions are used with one of the defined Err* constants you get back an error that you're able to pass the error through a GRPC server and client or use to build HTTP error messages and set the HTTP status.

Wrapping any error other than an Error will return an error with the message formatted as "<message>: <error>".

Wrapping an Error will return an error with an unaltered error message.

Transmitting errors over GRPC

The errors produced with wrap, that have also been wrapped first with an Err* can be send with SendGRPCError() and received with ReceiveGRPCError().

You may want to create and use GRPC server and client interceptors to avoid having to call the Send/Receive methods in every handler.

The Err* constants are errors and can be used directly is desired.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func As

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

As implements the standard errors.As for convenience

func Is

func Is(err, target error) bool

Is implements the standard errors.Is for convenience

func Message

func Message(err error) string

Message displays the string value for Error prefixed to the existing error message

Prefixed as "Error: message"

If err is not an Error or it hasn't wrapped one then there will no modifications made to the message.

Example
err := Wrap(ErrNotFound, "message")

fmt.Println(Message(err))
Output:

NOT_FOUND: message

func ReceiveGRPCError

func ReceiveGRPCError(err error) error

ReceiveGRPCError recreates the error with the coded Error reapplied

Non-nil results can be used as both Error and *status.Status. Methods errors.Is()/errors.As(), and status.Convert()/status.FromError() will continue to work.

Use in the clients when receiving errors. If err is nil then ReceiveGRPCError returns nil.

func SendGRPCError

func SendGRPCError(err error) error

SendGRPCError ensures that the error being used is sent with the correct code applied

Use in the server when sending errors. If err is nil then SendGRPCError returns nil.

func Unwrap

func Unwrap(err error) error

Unwrap implements the standard errors.Wrap for convenience

func Wrap

func Wrap(err error, msg string) error

Wrap returns an error with msg wrapped with the supplied error If err is nil then Wrap returns nil

Example
err := Wrap(ErrNotFound, "message")
fmt.Println(err)
Output:

message
Example (Multiple)
err := Wrap(ErrNotFound, "original message")
err = Wrap(err, "prefixed message")
fmt.Println(err)
Output:

prefixed message: original message

func Wrapf

func Wrapf(err error, format string, args ...interface{}) error

Wrapf returns an error with a formatted msg wrapped with the supplied error If err is nil then Wrapf returns nil

Types

type Error

type Error string

Error base error

const (
	ErrOK                  Error = "OK"                   // HTTP: 200 GRPC: codes.OK
	ErrCanceled            Error = "CANCELED"             // HTTP: 408 GRPC: codes.Canceled
	ErrUnknown             Error = "UNKNOWN"              // HTTP: 500 GRPC: codes.Unknown
	ErrInvalidArgument     Error = "INVALID_ARGUMENT"     // HTTP: 400 GRPC: codes.InvalidArgument
	ErrDeadlineExceeded    Error = "DEADLINE_EXCEEDED"    // HTTP: 504 GRPC: codes.DeadlineExceeded
	ErrNotFound            Error = "NOT_FOUND"            // HTTP: 404 GRPC: codes.NotFound
	ErrAlreadyExists       Error = "ALREADY_EXISTS"       // HTTP: 409 GRPC: codes.AlreadyExists
	ErrPermissionDenied    Error = "PERMISSION_DENIED"    // HTTP: 403 GRPC: codes.PermissionDenied
	ErrResourceExhausted   Error = "RESOURCE_EXHAUSTED"   // HTTP: 429 GRPC: codes.ResourceExhausted
	ErrFailedPrecondition  Error = "FAILED_PRECONDITION"  // HTTP: 400 GRPC: codes.FailedPrecondition
	ErrAborted             Error = "ABORTED"              // HTTP: 409 GRPC: codes.Aborted
	ErrOutOfRange          Error = "OUT_OF_RANGE"         // HTTP: 422 GRPC: codes.OutOfRange
	ErrUnimplemented       Error = "UNIMPLEMENTED"        // HTTP: 501 GRPC: codes.Unimplemented
	ErrInternal            Error = "INTERNAL_ERROR"       // HTTP: 500 GRPC: codes.Internal
	ErrUnavailable         Error = "UNAVAILABLE"          // HTTP: 503 GRPC: codes.Unavailable
	ErrDataLoss            Error = "DATA_LOSS"            // HTTP: 500 GRPC: codes.DataLoss
	ErrUnauthenticated     Error = "UNAUTHENTICATED"      // HTTP: 401 GRPC: codes.Unauthenticated
	ErrBadRequest          Error = "BAD_REQUEST"          // HTTP: 400 GRPC: codes.InvalidArgument
	ErrConflict            Error = "CONFLICT"             // HTTP: 409 GRPC: codes.AlreadyExists
	ErrUnauthorized        Error = "UNAUTHORIZED"         // HTTP: 401 GRPC: codes.Unauthenticated
	ErrForbidden           Error = "FORBIDDEN"            // HTTP: 403 GRPC: codes.PermissionDenied
	ErrUnprocessableEntity Error = "UNPROCESSABLE_ENTITY" // HTTP: 422 GRPC: codes.InvalidArgument
	ErrServer              Error = "SERVER_ERROR"         // HTTP: 500 GRPC: codes.Internal
	ErrClient              Error = "CLIENT_ERROR"         // HTTP: 400 GRPC: codes.InvalidArgument
)

Errors

func (Error) Error

func (e Error) Error() string

Error implements error

func (Error) Format

func (e Error) Format(s fmt.State, v rune)

Format implements fmt.Formatter

Error is embedded without modification to the error message with Wrap() and Wrapf() or manually with fmt.Errorf() using "%-w".

func (Error) GRPCCode

func (e Error) GRPCCode() codes.Code

func (Error) HTTPCode

func (e Error) HTTPCode() int

type GRPCCoder

type GRPCCoder interface {
	GRPCCode() codes.Code
}

type HTTPCoder

type HTTPCoder interface {
	HTTPCode() int
}

Jump to

Keyboard shortcuts

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