Documentation

Overview

Package appstatus can attach/reterieve an application-specific response status to/from an error. It designed to prevent accidental exposure of internal statuses to RPC clients, for example Spanner's statuses.

Attaching a status

Use ToError, Error and Errorf to create new status-annotated errors. Use Attach and Attachf to annotate existing errors with a status.

if req.PageSize < 0  {
   return appstatus.Errorf(codes.InvalidArgument, "page size cannot be negative")
}
if err := checkState(); err != nil {
  return appstatus.Attachf(err, codes.PreconditionFailed, "invalid state")
}

This may be done deep in the function call hierarchy.

Do not use appstatus in code where you don't explicitly intend to return a specific status. This is unnecessary because any unrecognized error is treated as internal and because it is explicitly prohibited to attach a status to an error chain multiple times. When a status is attached, the package supports its propagation all the way to the requester unless there is code that explicitly throws it away.

Returning a status

Use GRPCifyAndLog right before returning the error from a gRPC method handler. Usually it is done in a Postlude of a service decorator, see ../cmd/svcdec.

func NewMyServer() pb.MyServer {
  return &pb.DecoratedMyServer{
    Service:  &actualImpl{},
    Postlude: func(ctx context.Context, methodName string, rsp proto.Message, err error) error {
      return appstatus.GRPCifyAndLog(ctx, err)
    },
  }
}

It recognizes only appstatus-annotated errors and treats any other error as internal. This behavior is important to avoid accidentally returning errors from Spanner or other client library that also uses grpc/status package to communicate status code from *other* services. For example, if a there is a typo in Spanner SQL statement, spanner package may return a status-annotated errors with code NotFound. In this case, our RPC must respond with internal error and not NotFound.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Attach

func Attach(err error, status *status.Status) error

Attach attaches an application-specific status to the error. The status will be shared with the RPC client as is. If err already has an application-specific status attached, panics.

func Attachf

func Attachf(err error, code codes.Code, format string, args ...interface{}) error

Attachf is a shortcut for Attach(err, status.Newf(...))

func BadRequest

func BadRequest(err error, details ...*errdetails.BadRequest) error

BadRequest annotates err as a bad request. The error message is shared with the requester as is.

func Error

func Error(code codes.Code, msg string) error

Error returns an error with an application-specific status. The message will be shared with the RPC client as is.

func Errorf

func Errorf(code codes.Code, format string, args ...interface{}) error

Errorf returns an error with an application-specific status. The message will be shared with the RPC client as is.

func GRPCifyAndLog

func GRPCifyAndLog(ctx context.Context, err error) error

GRPCifyAndLog returns a GRPC error. If the error doesn't have a GRPC status attached by this package, internal error is assumed. Any internal or unknown errors are logged.

func Get

func Get(err error) (st *status.Status, ok bool)

Get returns an application-specific Status attached to err using this package. If not explicitly set or if err is nil, then ok is false.

func MustWithDetails

func MustWithDetails(s *status.Status, details ...proto.Message) *status.Status

MustWithDetails adds details to a status and asserts it is successful.

func ToError

func ToError(s *status.Status) error

ToError converts an application-specific status to an error.

Types

This section is empty.