rfc7807

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2019 License: MIT Imports: 5 Imported by: 1

README

RFC 7807

GoDoc

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)
Install

go get github.com/longkai/rfc7807

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

	// The service is currently unavailable.  This is most likely a
	// 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.

Jump to

Keyboard shortcuts

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