Documentation
¶
Overview ¶
Package errors provides structured API error types that integrate with Go's standard errors package (errors.Is, errors.As, error wrapping).
Usage:
err := errors.New(errors.CodeNotFound, "user not found")
err = err.WithStatus(404).WithDetail("user_id", "abc123")
// In handlers:
if errors.Is(err, errors.ErrNotFound) { ... }
// Automatic HTTP response:
var apiErr *errors.Error
if errors.As(err, &apiErr) {
apiErr.StatusCode // 404
}
Index ¶
- Constants
- Variables
- func ErrorCode(err error) string
- func HTTPStatus(err error) int
- func RegisterCode(code string, status int)
- type Error
- func BadRequest(message string) *Error
- func Conflict(message string) *Error
- func Forbidden(message string) *Error
- func From(err error) *Error
- func Fromf(err error, code string, format string, args ...any) *Error
- func Internal(message string) *Error
- func Internalf(err error, message string) *Error
- func New(code string, message string) *Error
- func Newf(code string, format string, args ...any) *Error
- func NotFound(resource string) *Error
- func RateLimited(message string) *Error
- func ServiceUnavailable(message string) *Error
- func Timeout(message string) *Error
- func Unauthorized(message string) *Error
- func Validation(message string, fields map[string]string) *Error
- func (e *Error) Error() string
- func (e *Error) Is(target error) bool
- func (e *Error) Unwrap() error
- func (e *Error) WithDetail(key string, value any) *Error
- func (e *Error) WithDetails(details map[string]any) *Error
- func (e *Error) WithField(field, message string) *Error
- func (e *Error) WithFields(fields map[string]string) *Error
- func (e *Error) WithMessage(msg string) *Error
- func (e *Error) WithStatus(status int) *Error
- func (e *Error) Wrap(err error) *Error
Constants ¶
const ( // Client errors (4xx) CodeBadRequest = "BAD_REQUEST" CodeForbidden = "FORBIDDEN" CodeNotFound = "NOT_FOUND" CodeMethodNotAllowed = "METHOD_NOT_ALLOWED" CodeConflict = "CONFLICT" CodeGone = "GONE" CodeValidation = "VALIDATION_ERROR" CodeRateLimited = "RATE_LIMITED" CodeRequestTooLarge = "REQUEST_TOO_LARGE" CodeUnsupportedMedia = "UNSUPPORTED_MEDIA_TYPE" CodeUnprocessable = "UNPROCESSABLE_ENTITY" CodeTooManyRequests = "TOO_MANY_REQUESTS" CodeInvalidCredentials = "INVALID_CREDENTIALS" CodeTokenExpired = "TOKEN_EXPIRED" CodeTokenInvalid = "TOKEN_INVALID" CodeEmailNotVerified = "EMAIL_NOT_VERIFIED" CodeInsufficientScope = "INSUFFICIENT_SCOPE" CodeResourceLocked = "RESOURCE_LOCKED" CodePreconditionFailed = "PRECONDITION_FAILED" CodeIdempotencyConflict = "IDEMPOTENCY_CONFLICT" // Server errors (5xx) CodeInternal = "INTERNAL_ERROR" CodeNotImplemented = "NOT_IMPLEMENTED" CodeTimeout = "TIMEOUT" CodeDatabaseError = "DATABASE_ERROR" CodeExternalService = "EXTERNAL_SERVICE_ERROR" // Business logic errors CodeInsufficientFunds = "INSUFFICIENT_FUNDS" CodeQuotaExceeded = "QUOTA_EXCEEDED" CodeOperationNotAllowed = "OPERATION_NOT_ALLOWED" CodeDuplicateEntry = "DUPLICATE_ENTRY" )
Standard error codes. Use these as the Code field in Error for consistency across your API.
Variables ¶
var ( ErrBadRequest = &Error{Code: CodeBadRequest} ErrForbidden = &Error{Code: CodeForbidden} ErrNotFound = &Error{Code: CodeNotFound} ErrConflict = &Error{Code: CodeConflict} ErrValidation = &Error{Code: CodeValidation} ErrRateLimited = &Error{Code: CodeRateLimited} ErrInternal = &Error{Code: CodeInternal} ErrTokenExpired = &Error{Code: CodeTokenExpired} ErrTokenInvalid = &Error{Code: CodeTokenInvalid} ErrInvalidCreds = &Error{Code: CodeInvalidCredentials} ErrResourceLocked = &Error{Code: CodeResourceLocked} ErrDuplicateEntry = &Error{Code: CodeDuplicateEntry} ErrQuotaExceeded = &Error{Code: CodeQuotaExceeded} ErrTimeout = &Error{Code: CodeTimeout} ErrExternalService = &Error{Code: CodeExternalService} ErrInsufficientFund = &Error{Code: CodeInsufficientFunds} )
Sentinel errors for use with errors.Is().
Usage:
if errors.Is(err, apikit.ErrNotFound) {
// handle not found
}
These sentinels only match on Code, not on Message. This means New(CodeNotFound, "user not found") will match ErrNotFound.
Functions ¶
func HTTPStatus ¶
HTTPStatus returns the status code, or 500 if the error is not an *Error.
func RegisterCode ¶
RegisterCode registers a custom error code with its default HTTP status. It is safe for concurrent use.
func init() {
errors.RegisterCode("SUBSCRIPTION_EXPIRED", 402)
}
Types ¶
type Error ¶
type Error struct {
// StatusCode is the HTTP status code to respond with.
StatusCode int `json:"status_code"`
// Code is a machine-readable error code (e.g., "NOT_FOUND", "VALIDATION_ERROR").
Code string `json:"code"`
// Message is a human-readable error description.
Message string `json:"message"`
// Fields contains field-level validation errors.
// Key is the field name, value is the error description.
Fields map[string]string `json:"fields,omitempty"`
// Details contains arbitrary additional error metadata.
Details map[string]any `json:"details,omitempty"`
// Err is the underlying wrapped error.
Err error `json:"-"`
// Stack holds the caller information for debugging.
Stack string `json:"-"`
}
Error represents a structured API error. It implements the error interface and supports Go's error wrapping.
func BadRequest ¶
BadRequest creates a 400 Bad Request error.
func From ¶
From wraps a standard error into an API Error. If the error is already an *Error, it is returned as-is. Otherwise, it wraps the error as an internal server error.
func Internal ¶
Internal creates a 500 Internal Server Error. The message provided should be safe to expose to clients. Wrap the original error using .Wrap(err) for logging.
func Internalf ¶
Internalf creates a 500 error wrapping the original error. The original error is NOT exposed to clients; only the message is.
func New ¶
New creates a new Error with the given code and message. It captures the caller's location for debugging.
func NotFound ¶
NotFound creates a 404 Not Found error. If resource is provided, the message will be "<resource> not found".
func RateLimited ¶
RateLimited creates a 429 Too Many Requests error.
func ServiceUnavailable ¶
ServiceUnavailable creates a 503 Service Unavailable error.
func Unauthorized ¶
Unauthorized creates a 401 Unauthorized error.
func Validation ¶
Validation creates a 422 Validation error with field errors.
func (*Error) Is ¶
Is reports whether target matches this error's Code. This allows errors.Is(err, ErrNotFound) to work even when messages differ.
func (*Error) WithDetail ¶
WithDetail adds a single detail entry on a copy of the error.
func (*Error) WithDetails ¶
WithDetails sets the details map on a copy of the error.
func (*Error) WithFields ¶
WithFields sets multiple field errors on a copy of the error.
func (*Error) WithMessage ¶
WithMessage replaces the error message on a copy of the error.
func (*Error) WithStatus ¶
WithStatus sets the HTTP status code on a copy of the error.