Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

License

NotificationsYou must be signed in to change notification settings

stackus/errors

Repository files navigation

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.20 or later is required to use this package.

Embeddable codes

This library allows the use and helps facilitate the embedding of a type code, HTTP status, and GRPC code into errorsthat can then be shared between services.

Type Codes

Type codes are strings that are returned by any error that implementserrors.TypeCoder.

type TypeCoder interface {    error    TypeCode() string}

HTTP Statuses

HTTP statuses are integer values that have defined in thenet/http package and are returned by any error thatimplementserrors.HTTPCoder.

type HTTPCoder interface {    error    HTTPCode() int}

GRPC Codes

GRPC codes arecodes.Code are int64 values defined in thegoogle.golang.org/grpc/codes package and are returned byany error that implementserrors.GRPCCoder.

type GRPCCoder interface {    error    GRPCCode() codes.Code}

Packaged Error Types

The package also comes with many defined errors that are named in a way to reflect the GRPC code or HTTP status theyrepresent. The list of embeddableerrors.Error types can befoundhere.

Wrapping errors

Theerrors.Wrap(error, string) error function is used to wrap errors combining messages in most cases. However, whenthe function is used with an error that has implementederrors.TypeCoder the message is not altered, and the error isembedded instead.

// Wrapping normal errors appends the error messageerr:=errors.Wrap(fmt.Errorf("sql error"),"error message")fmt.Println(err)// Outputs: "error message: sql error"// Wrapping errors.TypeCoder errors embeds the typeerr:=errors.Wrap(errors.ErrNotFound,"error message")fmt.Println(err)// Outputs: "error message"

Wrapping multiple times will add additional prefixes to the error message.

// Wrapping multiple timeserr:=errors.Wrap(errors.ErrNotFound,"error message")err=errors.Wrap(err,"prefix")err=errors.Wrap(err,"another")fmt.Println(err)// Outputs: "another: prefix: error message"

Wrapping using the errors.Err* errors

It is possible to use the package errors to wrap existing errors to add or override Type, HTTP code, or GRPC status codes.

// Err will use the wrapped error .Error() output as the messageerr:=errors.ErrBadRequest.Err(fmt.Errorf("some error"))// Msg and Msgf returns the Error with just the custom message appliederr=errors.ErrBadRequest.Msgf("%d total reasons",7)// Wrap and Wrapf will accept messages and simple wrap the errorerr=errors.ErrUnauthorized.Wrap(err,"some message")

Both errors can be checked for using theIs() andAs() methods when you wrap errors with the package errors this way.

Getting type, HTTP status, or GRPC code

The Go 1.13errors.As(error, interface{}) bool function from the standarderrors package can be used to turn anerror into any of the three "Coder" interfaces documented above.

err := errors.Wrap(errors.NotFound, "error message")var coder errors.TypeCoderif errors.As(err, &coder) {    fmt.Println(coder.TypeCode()) // Outputs: "NOT_FOUND"}

The functionsIs(),As(), andUnwrap() from the standarderrors package have all been made available in this package as proxies for convenience.

The functionserrors.TypeCode(error) string,errors.HTTPCode(error) int, anderrors.GRPCCode(error) codes.Code canbe used to fetch specific code. They're more convenient to use than the interfaces directly. The catch is they havedefined rules for the values they return.

The functionerrors.Join(errs ...error) error, made available in Go 1.20 has been added to this package as an additional convenience.

errors.TypeCode(error) string

If the error implements or has wrapped an error that implementserrors.TypeCoder it will return the code from thaterror. If no error is found to support the interface then the string"UNKNOWN" is returned. Nil errors result in ablank string being returned.

fmt.Println(errors.TypeCode(errors.ErrNotFound)) // Outputs: "NOT_FOUND"fmt.Println(errors.TypeCode(fmt.Errorf("an error"))) // Outputs: "UNKNOWN"fmt.Println(errors.TypeCode(nil)) // Outputs: ""

errors.HTTPCode(error) int

If the error implements or has wrapped an error that implementserrors.HTTPCoder it will return the status from thaterror. If no error is found to support the interface thenhttp.StatusNotExtended is returned. Nil errors resultinhttp.StatusOK being returned.

fmt.Println(errors.HTTPCode(errors.ErrNotFound)) // Outputs: 404fmt.Println(errors.HTTPCode(fmt.Errorf("an error"))) // Outputs: 510fmt.Println(errors.HTTPCode(nil)) // Outputs: 200

errors.GRPCCode(error) codes.Code

If the error implements or has wrapped an error that implementserrors.GRPCCoder it will return the code from thaterror. If no error is found to support the interface thencodes.Unknown is returned. Nil errors result incodes.OKbeing returned.

fmt.Println(errors.GRPCCode(errors.ErrNotFound)) // Outputs: 5fmt.Println(errors.GRPCCode(fmt.Errorf("an error"))) // Outputs: 2fmt.Println(errors.GRPCCode(nil)) // Outputs: 0

Why Unknown? Why not default to internal errors?

Part of the reason you'd want to use a library that adds code to your errors is because you want to better identify theproblems in your application. By marking un-coded errors as "Unknown" errors they'll stand out from any errors you'vemarked ascodes.Internal for example.

Transmitting errors with GRPC

The functionsSendGRPCError(error) error andReceiveGRPCError(error) error provide a way to convertastatus.Status and its error into an error that provides codes and vice versa. You can use these in your server andclient handlers directly, or they can be used with GRPC interceptors.

Server Interceptor Example:

// Unary only examplefunc 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()), ...others)

Client Interceptor Example:

// Unary only examplefunc 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()), ...others)

Comparing received errors

Servers and clients may not always use a shared library when exchanging errors. In fact there isn't any requirement thatthe server and client both use this library to exchange errors.

When comparing received errors witherrors.Is(error, error) bool the checks are a little more loose. A received erroris considered to be the same ifANY of the codes are a match. This differs from a strict equality check for theserver before the error was sent.

The "Code" functions and the "Coder" interfaces continue to work the same on a client as they did on the server thatsent the error.

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

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp