Documentation
¶
Overview ¶
Package httperr provides HTTP-aware errors with RFC 7807 Problem Details support.
This package simplifies error handling in HTTP APIs by attaching HTTP status codes, custom error codes, and metadata to errors. It supports the standard Go error wrapping interface and provides utilities for writing errors to HTTP responses.
Basic usage:
err := httperr.HTTP(404, "user not found").
WithCode(httperr.CodeNotFound).
WithMetadata("user_id", id)
httperr.WriteJSON(w, err)
Using the Handler wrapper:
func GetUser(w http.ResponseWriter, r *http.Request) error {
user, err := db.FindUser(id)
if err != nil {
return httperr.HTTP(404, "user not found")
}
return json.NewEncoder(w).Encode(user)
}
http.Handle("/users/{id}", httperr.Handler(GetUser))
Index ¶
- Constants
- Variables
- func HandlerFunc(h Handler) http.HandlerFunc
- func RecoverHandler(next http.Handler) http.Handler
- func WriteJSON(w http.ResponseWriter, err error, opts ...HTTPOption)
- func WriteText(w http.ResponseWriter, err error)
- type Error
- func (e *Error) Code() string
- func (e *Error) Error() string
- func (e *Error) HTTPStatus() int
- func (e *Error) Metadata() map[string]any
- func (e *Error) Unwrap() error
- func (e *Error) WithCode(code string) *Error
- func (e *Error) WithMetadata(key string, value any) *Error
- func (e *Error) WithStatus(status int) *Error
- type HTTPOption
- type Handler
- type ProblemDetail
Constants ¶
const ( // Generic codes CodeInternal = "INTERNAL_ERROR" CodeUnknown = "UNKNOWN_ERROR" // Validation codes CodeValidation = "VALIDATION_ERROR" CodeInvalidInput = "INVALID_INPUT" CodeMissingField = "MISSING_FIELD" CodeInvalidFormat = "INVALID_FORMAT" // Resource codes CodeNotFound = "NOT_FOUND" CodeAlreadyExists = "ALREADY_EXISTS" CodeConflict = "CONFLICT" // Authentication/Authorization codes CodeForbidden = "FORBIDDEN" CodeInvalidToken = "INVALID_TOKEN" CodeExpiredToken = "EXPIRED_TOKEN" // Rate limiting codes CodeRateLimited = "RATE_LIMITED" CodeQuotaExceeded = "QUOTA_EXCEEDED" // Business logic codes CodeBusinessRule = "BUSINESS_RULE_VIOLATION" CodePrecondition = "PRECONDITION_FAILED" )
Common error codes that can be used across applications. These follow a SCREAMING_SNAKE_CASE convention common in error codes.
Variables ¶
var ( ErrBadRequest = New("bad request").WithStatus(400).WithCode(CodeInvalidInput) ErrValidation = New("validation failed").WithStatus(400).WithCode(CodeValidation) ErrForbidden = New("forbidden").WithStatus(403).WithCode(CodeForbidden) ErrNotFound = New("resource not found").WithStatus(404).WithCode(CodeNotFound) ErrConflict = New("resource conflict").WithStatus(409).WithCode(CodeConflict) ErrInternal = New("internal server error").WithStatus(500).WithCode(CodeInternal) )
Common pre-built errors with codes for convenience. These can be used directly or as base errors with additional methods chained.
Example:
return httperr.ErrNotFound.WithMetadata("user_id", id)
Functions ¶
func HandlerFunc ¶
func HandlerFunc(h Handler) http.HandlerFunc
HandlerFunc converts a Handler to http.HandlerFunc.
func RecoverHandler ¶
RecoverHandler is an HTTP middleware that recovers from panics and converts them to 500 errors.
Example:
mux := http.NewServeMux()
mux.HandleFunc("/", myHandler)
http.ListenAndServe(":8080", httperr.RecoverHandler(mux))
func WriteJSON ¶
func WriteJSON(w http.ResponseWriter, err error, opts ...HTTPOption)
WriteJSON writes an error as JSON to an HTTP response. It uses RFC 7807 Problem Details format and sets the appropriate Content-Type header (application/problem+json).
If err is nil, this function does nothing.
Example:
err := httperr.HTTP(404, "user not found").WithCode(httperr.CodeNotFound) httperr.WriteJSON(w, err)
func WriteText ¶
func WriteText(w http.ResponseWriter, err error)
WriteText writes an error as plain text to an HTTP response. It extracts the HTTP status code from httperr.Error types, or defaults to 500 for other error types.
If err is nil, this function does nothing.
Example:
err := httperr.HTTP(404, "user not found") httperr.WriteText(w, err)
Types ¶
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error represents an HTTP-aware error with support for status codes, custom error codes, and metadata. It implements the standard error interface and supports wrapping.
func New ¶
New creates a new Error with the given message. This is compatible with errors.New from the standard library.
func Wrap ¶
Wrap wraps an existing error with a message. This is similar to fmt.Errorf with %w but returns *Error. If err is nil, returns nil.
func (*Error) HTTPStatus ¶
HTTPStatus returns the HTTP status code associated with this error. Returns 500 (Internal Server Error) if no status was set.
func (*Error) Metadata ¶
Metadata returns a copy of the error metadata to prevent external mutation.
func (*Error) WithCode ¶
WithCode returns a new Error with the specified error code. This method is immutable and returns a new instance.
func (*Error) WithMetadata ¶
WithMetadata returns a new Error with the specified metadata merged in. This method is immutable and returns a new instance.
func (*Error) WithStatus ¶
WithStatus returns a new Error with the specified HTTP status code. This method is immutable and returns a new instance.
type HTTPOption ¶
type HTTPOption func(*httpConfig)
HTTPOption configures how errors are written to HTTP responses.
func WithTypePrefix ¶
func WithTypePrefix(prefix string) HTTPOption
WithTypePrefix sets a prefix for RFC 7807 type URIs. This is useful for creating domain-specific error type URIs.
Example:
WriteJSON(w, err, WithTypePrefix("https://example.com/errors/"))
// Type becomes: https://example.com/errors/VALIDATION_ERROR
type Handler ¶
type Handler func(w http.ResponseWriter, r *http.Request) error
Handler wraps an http.HandlerFunc that returns an error. It automatically handles error responses using WriteJSON.
This allows writing HTTP handlers that return errors instead of manually writing error responses.
Example:
func GetUser(w http.ResponseWriter, r *http.Request) error {
user, err := db.FindUser(id)
if err != nil {
return httperr.HTTP(404, "user not found")
}
json.NewEncoder(w).Encode(user)
return nil
}
http.Handle("/users/:id", httperr.Handler(GetUser))
type ProblemDetail ¶
type ProblemDetail struct {
// Type is a URI reference [RFC3986] that identifies the problem type.
// When dereferenced, it SHOULD provide human-readable documentation for
// the problem type. When this member is not present, its value is assumed
// to be "about:blank".
Type string `json:"type,omitempty"`
// Title is a short, human-readable summary of the problem type.
// It SHOULD NOT change from occurrence to occurrence of the problem,
// except for purposes of localization.
Title string `json:"title,omitempty"`
// Status is the HTTP status code generated by the origin server for this
// occurrence of the problem.
Status int `json:"status,omitempty"`
// Detail is a human-readable explanation specific to this occurrence of
// the problem.
Detail string `json:"detail,omitempty"`
// Instance is a URI reference that identifies the specific occurrence of
// the problem. It may or may not yield further information if dereferenced.
Instance string `json:"instance,omitempty"`
// Extensions contains additional problem-specific fields that are not
// part of the standard RFC 7807 fields. These will be serialized at the
// root level of the JSON object.
Extensions map[string]any `json:"-"`
}
ProblemDetail represents an RFC 7807 Problem Details object. See: https://www.rfc-editor.org/rfc/rfc7807
RFC 7807 defines a "problem detail" as a way to carry machine-readable details of errors in HTTP response content to avoid the need to define new error response formats for HTTP APIs.
func ToProblemDetail ¶
func ToProblemDetail(err error) ProblemDetail
ToProblemDetail converts an error to an RFC 7807 Problem Details object.
If the error is an httperr.Error, it extracts the HTTP status, error code, and metadata. Otherwise, it returns a generic 500 Internal Server Error.
func (ProblemDetail) MarshalJSON ¶
func (p ProblemDetail) MarshalJSON() ([]byte, error)
MarshalJSON implements custom JSON marshaling to include extensions at the root level of the JSON object.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
Package main demonstrates basic usage of httperr for creating and handling HTTP errors.
|
Package main demonstrates basic usage of httperr for creating and handling HTTP errors. |
|
handler
command
Package main demonstrates using httperr.Handler to write cleaner HTTP handlers that return errors.
|
Package main demonstrates using httperr.Handler to write cleaner HTTP handlers that return errors. |
|
middleware
command
Package main demonstrates using httperr middleware for panic recovery and centralized error handling.
|
Package main demonstrates using httperr middleware for panic recovery and centralized error handling. |
|
rfc7807
command
Package main demonstrates RFC 7807 Problem Details features, including custom type URIs and direct ProblemDetail usage.
|
Package main demonstrates RFC 7807 Problem Details features, including custom type URIs and direct ProblemDetail usage. |
|
validation
command
Package main demonstrates using httperr for request validation with detailed error responses.
|
Package main demonstrates using httperr for request validation with detailed error responses. |
|
wrapping
command
Package main demonstrates error wrapping with httperr, showing how to wrap lower-level errors while adding HTTP context.
|
Package main demonstrates error wrapping with httperr, showing how to wrap lower-level errors while adding HTTP context. |