Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

problemjson

Go Report Card Go Reference License: MIT

A Go implementation of RFC 7807 — Problem Details for HTTP APIs. *Problem implements http.Handler and can be mounted on any mux or called inline.

  • Pre-built constructors for all standard 4xx and 5xx status codes
  • Functional compositionNew, From, and option functions; no setters, no mutation
  • Extensions — arbitrary RFC 7807 top-level extension fields via With
  • Zero dependencies

Install

go get lowbit.dev/problemjson

Usage

// mount directly on a mux — Instance is set from r.URL.Path automatically
mux.Handle("/healthz", problem.ServiceUnavailable())

// inline in a handler
func handleGet(w http.ResponseWriter, r *http.Request) {
    problem.NotFound(
        problem.Detail("user 42 does not exist"),
    ).ServeHTTP(w, r)
}

// when you only have a ResponseWriter (tests, middleware)
problem.InternalServerError().Write(w)

Constructors

New builds a problem from scratch:

p := problem.New(
    problem.Status(http.StatusUnprocessableEntity),
    problem.Title("Validation failed"),
    problem.Detail("the request body failed schema validation"),
    problem.With("field", "email"),
    problem.With("constraint", "must be a valid email address"),
)
p.ServeHTTP(w, r)

From derives a new problem from an existing one without mutating it — safe for package-level bases:

var ErrOutOfStock = problem.NotFound(problem.Title("Product not available"))

func handleOrder(w http.ResponseWriter, r *http.Request) {
    problem.From(ErrOutOfStock,
        problem.Detailf("product %q is out of stock", productID),
    ).ServeHTTP(w, r)
}

Options

Option Sets
Status(int) HTTP status code
Title(string) Short human-readable summary
Titlef(string, ...any) Title with fmt.Sprintf formatting
Detail(string) Longer explanation
Detailf(string, ...any) Detail with fmt.Sprintf formatting
Type(string) URI identifying the problem type
Typef(string, ...any) Type with fmt.Sprintf formatting
Instance(string) URI identifying the specific occurrence
InstanceFromRequest(*http.Request) Sets instance to r.URL.Path
With(key, value) Arbitrary RFC 7807 extension field
Error(error) Extension field "reason" set to err.Error()

Extensions

Extension fields appear at the top level of the JSON object, as required by RFC 7807:

// produces: {"type":"...","status":422,"title":"...","field":"email","reason":"invalid format"}
problem.New(
    problem.Status(422),
    problem.Title("Validation failed"),
    problem.With("field", "email"),
    problem.Error(err),
)

About

A Go implementation of RFC 7807: Problem Details for HTTP APIs

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages