Overview
httperr is a standalone Go module (github.com/gp-system/httperr): the wire-facing side of the gpsystem error model, turning a Go error into an RFC 9457 problem+json HTTP response. It depends on gp-system/errs (for reading a built error's code, public message and status) and go-playground/validator (via the httperr/validate subpackage, for turning struct-tag validation failures into the same shape). It works with plain net/http: no framework required. Building the errors it renders is errs's job, covered on the Error model page; this page and the two after it cover rendering.
Install
go get github.com/gp-system/httperr@v0.1.0 # the kit itself uses this tag
go get github.com/gp-system/httperr@latest
Go 1.25+. Dependencies: github.com/gp-system/errs and github.com/go-playground/validator/v10 (only pulled in transitively if you import httperr/validate; the base httperr package needs just errs).
The Problem type
import "github.com/gp-system/httperr"
type Problem struct {
Type string `json:"type"`
Title string `json:"title"`
Status int `json:"status"`
Detail string `json:"detail,omitempty"`
Instance string `json:"instance,omitempty"`
Code string `json:"code,omitempty"`
Errors []FieldError `json:"errors,omitempty"`
}
type FieldError struct {
Field string `json:"field"`
Rule string `json:"rule,omitempty"`
Message string `json:"message"`
}
Problem implements error, so you can build one and return it directly from a handler like any other error; the next page covers how it (and every other error) actually reaches the HTTP response. A worked example, in full:
if productID == "" {
return httperr.BadRequest("productId is required")
}
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "productId is required"
}
Constructors
httperr.New(status, title, detail) // title defaults to the HTTP status text
httperr.BadRequest(detail) // 400
httperr.Unauthorized(detail) // 401
httperr.Forbidden(detail) // 403
httperr.NotFound(detail) // 404
httperr.Conflict(detail) // 409
httperr.Internal(detail) // 500
httperr.Validation(fieldErrs...) // 422, with errors[]
These cover quick, anonymous 4xx cases well: return httperr.NotFound("no such product") in a handler is perfectly fine as-is. As soon as a failure mode has a name, a stable code, or more than one call site, errs.Define is the better home for it: recognition (errors.Is) and rendering (status, code, message) then live in one declaration instead of scattered httperr.___(...) calls, and the mapping picks it up the same way.
Related pages
- Error responses:
WriteError/NewWriteError, the full mapping order, and howHTTP_EXPOSE_INTERNAL_ERRORSfits in. - Validation: the
httperr/validatepackage,Translate, and the 422 response shape. - errs: Overview: the module that builds the errors
httperrrenders. - Error model: the whole request-to-response pipeline.