problem

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 10 Imported by: 1

Documentation

Overview

Package problem implements RFC 9457 problem details with stable codes that clients localize on.

A problem's type is either "about:blank", meaning nothing beyond its HTTP status, or a Type defined in a Registry, served as a relative URI such as "/problems/shop/name_taken". Every defined type has a Code, a short snake_case name that clients use as a message key. For an about:blank problem, clients derive the code from the status with CodeForStatus.

Index

Constants

View Source
const Blank = "about:blank"

Blank is the problem type for a problem with no semantics beyond its status.

View Source
const MediaType = "application/problem+json"

MediaType is the RFC 9457 media type for a problem details object.

Variables

View Source
var (
	Invalid = rule("invalid", "Invalid value",
		"The value is not valid for this field.")
	Required = rule("required", "Value required",
		"The field is required and was missing or empty.")
	TooShort = rule("too_short", "Value too short",
		"The value has fewer characters than the field allows.", "min")
	TooLong = rule("too_long", "Value too long",
		"The value has more characters than the field allows.", "max")
	TooFew = rule("too_few", "Too few items",
		"The list has fewer items than the field allows.", "min")
	TooMany = rule("too_many", "Too many items",
		"The list has more items than the field allows.", "max")
	BelowMinimum = rule("below_minimum", "Number too small",
		"The number is below the field's minimum. exclusive is \"true\" when the minimum itself is not allowed.", "min", "exclusive")
	AboveMaximum = rule("above_maximum", "Number too large",
		"The number is above the field's maximum. exclusive is \"true\" when the maximum itself is not allowed.", "max", "exclusive")
	InvalidFormat = rule("invalid_format", "Invalid format",
		"The value does not have the field's format, such as an email address, a URI or a date.")
	InvalidChoice = rule("invalid_choice", "Not an allowed value",
		"The value is not one of the field's allowed values, listed in allowed.", "allowed")
	InvalidType = rule("invalid_type", "Wrong type",
		"The value has the wrong JSON type, such as a string where a number belongs.")
	UnexpectedField = rule("unexpected_field", "Unknown field",
		"The request has a field the operation does not accept.")
	DuplicateItems = rule("duplicate_items", "Duplicate items",
		"The list has the same item more than once.")
)

The rules a field can fail. They are shared by every application, so their URIs are /problems/<code>. An application whose field fails a check of its own uses one of its Types instead.

Rules lists every rule, in the order above.

StatusCodes lists the codes CodeForStatus returns.

View Source
var Validation = rule("validation", "Invalid request",
	"One or more fields in the request are invalid. Each entry in errors names the field and the rule it failed.")

Validation is the problem for a request with invalid fields. Its Errors list each one, typed with a rule.

Functions

func Denied

func Denied(err error) bool

Denied reports whether err is, or wraps, a problem marked with AsDenial.

func Handler

func Handler(registries ...*Registry) http.Handler

Handler serves the documentation pages the problem type URIs resolve to: /problems/ lists every type, /problems/<code> documents a shared rule, and /problems/<name>/<code> a type in the registry called name. Mount it at /problems/ on the host that serves the API.

func Pointer

func Pointer(path ...any) string

Pointer returns the JSON Pointer (RFC 6901) to a body field, in the URI fragment form RFC 9457's example uses: Pointer("items", 3, "name") is "#/items/3/name". Pointer() is the whole body, "#".

func Write

func Write(w http.ResponseWriter, p *Problem)

Write sends p as the response.

Types

type Code

type Code string

Code is a problem type's stable, machine-readable name. Clients key their messages on it, so a code is part of the API contract: never rename one. The set is open: a client that meets a code it doesn't know falls back to the one for the status.

const (
	InvalidRequest  Code = "invalid_request"
	Unauthenticated Code = "unauthenticated"
	Forbidden       Code = "forbidden"
	NotFound        Code = "not_found"
	Conflict        Code = "conflict"
	RateLimited     Code = "rate_limited"
	Internal        Code = "internal"
	Unavailable     Code = "unavailable"
)

The codes clients derive from the status of an about:blank problem. They are never sent, since about:blank has no members beyond RFC 9457's own.

func CodeForStatus

func CodeForStatus(status int) Code

CodeForStatus is the code for an about:blank problem with the given status.

type FieldError

type FieldError struct {
	Type      string         `json:"type" format:"uri-reference" doc:"The rule's problem type."`
	Code      Code           `` /* 160-byte string literal not displayed */
	Detail    string         `json:"detail,omitempty" doc:"English explanation, for developers and logs."`
	Pointer   string         `json:"pointer,omitempty" doc:"JSON Pointer to the invalid body field, as a URI fragment such as #/items/0/name."`
	Parameter string         `json:"parameter,omitempty" doc:"Name of the invalid request parameter."`
	In        string         `json:"in,omitempty" enum:"query,path,header,cookie" doc:"Where parameter is."`
	Params    map[string]any `json:"params,omitempty" doc:"Values the rule's localized message shows."`
	// contains filtered or unexported fields
}

FieldError is one entry in a validation problem's errors, the extension RFC 9457 §3 uses in its validation example. Pointer locates a field in the request body; Parameter and In locate a query, path, header or cookie parameter instead.

func (*FieldError) Error

func (e *FieldError) Error() string

Error makes a FieldError an error, so a huma Resolver can return one.

func (FieldError) MarshalJSON added in v0.7.0

func (e FieldError) MarshalJSON() ([]byte, error)

MarshalJSON encodes a field error missing a param its type's message needs as Invalid, so a client never shows a message with a placeholder it cannot fill.

func (*FieldError) With

func (e *FieldError) With(key string, value any) *FieldError

With adds a value the field error's localized message shows.

type Problem

type Problem struct {
	Type     string         `` /* 148-byte string literal not displayed */
	Title    string         `json:"title,omitempty" doc:"Short English summary of the problem type, for developers."`
	Status   int            `json:"status,omitempty" doc:"The HTTP status code."`
	Detail   string         `json:"detail,omitempty" doc:"English explanation of this occurrence, for developers and logs."`
	Instance string         `json:"instance,omitempty" format:"uri-reference" doc:"Identifies this occurrence of the problem."`
	Code     Code           `` /* 222-byte string literal not displayed */
	Params   map[string]any `json:"params,omitempty" doc:"Values the code's localized message shows."`
	Errors   []*FieldError  `json:"errors,omitempty" doc:"For a validation problem, each invalid field and the rule it failed."`
	// contains filtered or unexported fields
}

Problem is an RFC 9457 problem details object. Title, Detail and each FieldError's Detail are English, for developers and logs; clients show the message for Code instead.

func Status

func Status(status int, detail string) *Problem

Status returns an about:blank problem: one the status fully describes.

func ValidationFailed

func ValidationFailed(errs ...*FieldError) *Problem

ValidationFailed returns a Validation problem listing errs.

func (*Problem) AsDenial

func (p *Problem) AsDenial() *Problem

AsDenial marks p as a refusal to authorize, so callers can tell it from a failure to work out the answer, such as an unreachable database, which must never be reported as a permission problem. It changes nothing sent.

func (*Problem) ContentType

func (p *Problem) ContentType(string) string

ContentType makes huma serve a Problem as application/problem+json.

func (*Problem) Error

func (p *Problem) Error() string

func (*Problem) GetStatus

func (p *Problem) GetStatus() int

GetStatus returns the HTTP status, so a Problem is a huma.StatusError.

func (*Problem) Key

func (p *Problem) Key() Code

Key is the code clients localize on: Code, or for an about:blank problem, the code its status implies.

func (Problem) MarshalJSON added in v0.7.0

func (p Problem) MarshalJSON() ([]byte, error)

MarshalJSON encodes the problem as Resolve returns it.

func (*Problem) Resolve added in v0.7.0

func (p *Problem) Resolve() *Problem

Resolve returns p as clients receive it. A problem missing a param its type's message needs is sent as the about:blank problem for its status, so a client never shows a message with a placeholder it cannot fill. MarshalJSON sends the resolved problem.

func (*Problem) Unwrap

func (p *Problem) Unwrap() error

Unwrap returns the cause attached with WithCause.

func (*Problem) With

func (p *Problem) With(key string, value any) *Problem

With adds a value the problem's localized message shows.

func (*Problem) WithCause

func (p *Problem) WithCause(err error) *Problem

WithCause attaches the underlying error, for logs. It is never sent.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds the problem types of one application. Their URIs are /problems/<name>/<code>, so a host that mounts several applications serves all their pages without collisions.

func NewRegistry

func NewRegistry(name string) *Registry

NewRegistry returns an empty registry for the application name, such as "shop". It panics if name is not a lowercase URI segment.

func (*Registry) Define

func (r *Registry) Define(t Type) *Type

Define adds a type to the registry and returns it. Call it from package variable declarations: it panics on an invalid or duplicate code, or on one that collides with the codes this package defines.

func (*Registry) Lookup

func (r *Registry) Lookup(code Code) (*Type, bool)

Lookup returns the type with the given code.

func (*Registry) Name

func (r *Registry) Name() string

Name is the application name in the registry's URIs.

func (*Registry) Types

func (r *Registry) Types() []*Type

Types returns the registry's types in the order they were defined.

type Type

type Type struct {
	Code   Code
	Status int
	// Title is a short English summary that never varies between occurrences.
	Title string
	// Doc explains, in English, what causes the problem and how to resolve it.
	Doc string
	// Params names the values the type's localized message shows.
	Params []string
	// contains filtered or unexported fields
}

Type is a problem type (RFC 9457 §4): a URI, a short title and the status it is used with. Define one with Registry.Define.

func (*Type) At

func (t *Type) At(pointer, detail string) *FieldError

At returns a field error of this type for the body field at pointer, which Pointer builds.

func (*Type) AtParameter

func (t *Type) AtParameter(in, name, detail string) *FieldError

AtParameter returns a field error of this type for a request parameter. in is "query", "path", "header" or "cookie", as in OpenAPI.

func (*Type) New

func (t *Type) New(detail string) *Problem

New returns a problem of this type.

func (*Type) Newf

func (t *Type) Newf(format string, args ...any) *Problem

Newf returns a problem of this type with a formatted detail.

func (*Type) URI

func (t *Type) URI() string

URI is the type's relative URI, which resolves to its documentation page.

Directories

Path Synopsis
Package humaproblem makes huma produce problem details: every error huma builds, including request validation, becomes a *problem.Problem, and the OpenAPI document lists the codes clients localize on.
Package humaproblem makes huma produce problem details: every error huma builds, including request validation, becomes a *problem.Problem, and the OpenAPI document lists the codes clients localize on.
Package problemrules holds go-ruleguard rules that keep internal errors out of problem responses.
Package problemrules holds go-ruleguard rules that keep internal errors out of problem responses.
Package problemtest checks that a client's message catalog covers an application's problem types.
Package problemtest checks that a client's message catalog covers an application's problem types.

Jump to

Keyboard shortcuts

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