Documentation ¶
Overview ¶
Package rfc7807 implements RFC 7807, Problem Details for HTTP APIs:
https://tools.ietf.org/html/rfc7807.
This package predefined Google's gRPC canonical error codes:
https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto.
To create a new problem detail:
rfc7807.New(rfc7807.NotFound, "xxx is not found.")
Or wrap with a underlying error:
rfc7807.Wrap(rfc7807.Internal, "", causeError)
It supports Go 2 error as values proposal:
https://go.googlesource.com/proposal/+/master/design/29934-error-values.md.
If the predefined errors doesn't satisfy your needs:
rfc7807.Customize("my.error.domain", "MY_ERROR_TYPE", 400, nil, nil)
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Code ¶
type Code int
Code represent the gRPC standard error codes.
const ( // The operation was cancelled, typically by the caller. // // HTTP Mapping: 499 Client Closed Request Cancelled Code // Unknown error. For example, this error may be returned when // a `Status` value received from another address space belongs to // an error space that is not known in this address space. Also // errors raised by APIs that do not return enough error information // may be converted to this error. // // HTTP Mapping: 500 Internal Server Error Unknown // The client specified an invalid argument. Note that this differs // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments // that are problematic regardless of the state of the system // (e.g., a malformed file name). // // HTTP Mapping: 400 Bad Request InvalidArgument // The deadline expired before the operation could complete. For operations // that change the state of the system, this error may be returned // even if the operation has completed successfully. For example, a // successful response from a server could have been delayed long // enough for the deadline to expire. // // HTTP Mapping: 504 Gateway Timeout DeadlineExceeded // Some requested entity (e.g., file or directory) was not found. // // Note to server developers: if a request is denied for an entire class // of users, such as gradual feature rollout or undocumented whitelist, // `NOT_FOUND` may be used. If a request is denied for some users within // a class of users, such as user-based access control, `PERMISSION_DENIED` // must be used. // // HTTP Mapping: 404 Not Found NotFound // The entity that a client attempted to create (e.g., file or directory) // already exists. // // HTTP Mapping: 409 Conflict AlreadyExists // The caller does not have permission to execute the specified // operation. `PERMISSION_DENIED` must not be used for rejections // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` // instead for those errors). `PERMISSION_DENIED` must not be // used if the caller can not be identified (use `UNAUTHENTICATED` // instead for those errors). This error code does not imply the // request is valid or the requested entity exists or satisfies // other pre-conditions. // // HTTP Mapping: 403 Forbidden PermissionDenied // Some resource has been exhausted, perhaps a per-user quota, or // perhaps the entire file system is out of space. // // HTTP Mapping: 429 Too Many Requests ResourceExhausted // Service implementors can use the following guidelines to decide // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: // (a) Use `UNAVAILABLE` if the client can retry just the failing call. // (b) Use `ABORTED` if the client should retry at a higher level // (e.g., when a client-specified test-and-set fails, indicating the // client should restart a read-modify-write sequence). // (c) Use `FAILED_PRECONDITION` if the client should not retry until // the system state has been explicitly fixed. E.g., if an "rmdir" // fails because the directory is non-empty, `FAILED_PRECONDITION` // should be returned since the client should not retry unless // the files are deleted from the directory. // // HTTP Mapping: 400 Bad Request FailedPrecondition // The operation was aborted, typically due to a concurrency issue such as // a sequencer check failure or transaction abort. // // See the guidelines above for deciding between `FAILED_PRECONDITION`, // `ABORTED`, and `UNAVAILABLE`. // // HTTP Mapping: 409 Conflict Aborted // The operation was attempted past the valid range. E.g., seeking or // reading past end-of-file. // // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may // be fixed if the system state changes. For example, a 32-bit file // system will generate `INVALID_ARGUMENT` if asked to read at an // offset that is not in the range [0,2^32-1], but it will generate // `OUT_OF_RANGE` if asked to read from an offset past the current // file size. // // There is a fair bit of overlap between `FAILED_PRECONDITION` and // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific // error) when it applies so that callers who are iterating through // a space can easily look for an `OUT_OF_RANGE` error to detect when // they are done. // // HTTP Mapping: 400 Bad Request OutOfRange // The operation is not implemented or is not supported/enabled in this // service. // // HTTP Mapping: 501 Not Implemented Unimplemented // Internal errors. This means that some invariants expected by the // underlying system have been broken. This error code is reserved // for serious errors. // // HTTP Mapping: 500 Internal Server Error Internal // transient condition, which can be corrected by retrying with // a backoff. // // See the guidelines above for deciding between `FAILED_PRECONDITION`, // `ABORTED`, and `UNAVAILABLE`. // // HTTP Mapping: 503 Service Unavailable Unavailable // Unrecoverable data loss or corruption. // // HTTP Mapping: 500 Internal Server Error DataLoss // The request does not have valid authentication credentials for the // operation. // // HTTP Mapping: 401 Unauthorized Unauthenticated )
The canonical error codes for Google APIs. See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto In the futrue we may in transition to gRPC, at that time, this code generated by protocol buffers.
type ProblemDetail ¶
type ProblemDetail struct { Type string `json:"type" xml:"type"` Title string `json:"title" xml:"title"` Status int `json:"status" xml:"status"` Detail string `json:"detail" xml:"detail"` Instance string `json:"instance" xml:"instance"` Extensions interface{} `json:"extensions,omitempty" xml:"extensions,omitempty"` // contains filtered or unexported fields }
ProblemDetail is the entity of RFC 7807.
func Customize ¶
func Customize(domain, typo, title, detail string, status int, cause error, extensions interface{}) *ProblemDetail
Customize creates a limited domain rfc7807 problem detail. Note you should provide a domain to limit the namespace of the problem, since it's different from canonical error codes for Google APIs. So the problem type will be `domain.typo`. Each typo and title should correspond one-to-one. The cause may be nil if you do not have a cause error to wrap. The extensions normally nil if no additional infomation passing. Please consider using `New` or `Wrap` first, if they cannot convery your needs, then come back this func.
Example ¶
package main import ( "fmt" "github.com/longkai/rfc7807" ) func main() { err := rfc7807.Customize("com.example", "METHOD_NOT_ALLOWED", "The request method is not allowed.", "The api only allows HTTP GET, got POST.", 405, nil, nil) err.Instance = "example only, do not set this field" fmt.Println(err) }
Output: {"type":"com.example.METHOD_NOT_ALLOWED","title":"The request method is not allowed.","status":405,"detail":"The api only allows HTTP GET, got POST.","instance":"example only, do not set this field"}
func New ¶
func New(code Code, detail string) *ProblemDetail
New creates a new problem detail with the typo and detail without wrapping any error.
Example ¶
package main import ( "fmt" "github.com/longkai/rfc7807" ) func main() { err := rfc7807.New(rfc7807.NotFound, "the item is not found") err.Instance = "example only, do not set this field" fmt.Println(err) }
Output: {"type":"NOT_FOUND","title":"A specified resource is not found, or the request is rejected by undisclosed reasons, such as whitelisting.","status":404,"detail":"the item is not found","instance":"example only, do not set this field"}
func Wrap ¶
func Wrap(code Code, detail string, err error) *ProblemDetail
Wrap wraps the err with the typo and detail into a problem detail.
Example ¶
package main import ( "fmt" "io" "github.com/longkai/rfc7807" "golang.org/x/xerrors" ) func main() { cause := xerrors.Errorf("read /path/to/file: %w", io.EOF) err := rfc7807.Wrap(rfc7807.Internal, "", cause) err.Instance = "example only, do not set this field" // Note: the output prints the stacktrace of the error wrapping chain, so it won't be passed in other environment. // Just showing the wrapping output format. fmt.Printf("%+v\n", err) }
Output: {"type":"INTERNAL","title":"Internal server error. Typically a server bug.","status":500,"detail":"","instance":"example only, do not set this field"}: github.com/longkai/rfc7807_test.ExampleWrap /Users/longkai/Dropbox/src/rfc7807/example_test.go:20 - read /path/to/file: github.com/longkai/rfc7807_test.ExampleWrap /Users/longkai/Dropbox/src/rfc7807/example_test.go:19 - EOF
func (*ProblemDetail) Error ¶
func (e *ProblemDetail) Error() string
func (*ProblemDetail) Format ¶
func (e *ProblemDetail) Format(s fmt.State, v rune)
Format implements fmt.Formatter.
func (*ProblemDetail) FormatError ¶
func (e *ProblemDetail) FormatError(p xerrors.Printer) (next error)
FormatError implements xerrors.Formatter.
func (*ProblemDetail) Unwrap ¶
func (e *ProblemDetail) Unwrap() error
Unwrap implements xerrors.Wrapper.