httpapi

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 13 Imported by: 0

README

httpapi

import "github.com/brpaz/lib-go/httpapi"

Package httpapi provides helpers for building JSON HTTP APIs.

It covers request decoding, structured error responses, and response writing. Error handling maps [errs.Error] domain errors to HTTP status codes and structured JSON bodies without leaking internal details to clients.

Request decoding
body, err := httpapi.DecodeJSON[CreateUserRequest](r)
if err != nil {
	httpapi.HandleErr(w, r, err, nil)
	return
}
Error handling

HandleErr maps any error to a JSON response. It understands [errs.Error] values extracted from the chain, JSON decode errors, and falls back to 500 for unknown errors. App-specific error codes are supported via extraCodes:

var appCodes = map[string]int{
	"payment_failed": http.StatusPaymentRequired,
}

httpapi.HandleErr(w, r, err, appCodes)

For [validator.ValidationError] from request validation, use HandleValidationError to tag each field error with its request location (body, query, path, header):

httpapi.HandleValidationError(w, r, httpapi.LocationBody, ve)
Response writing
httpapi.Ok(w, data)         // 200
httpapi.Created(w, data)    // 201
httpapi.NoContent(w)        // 204

Index

func Accepted

func Accepted(w http.ResponseWriter, data any)

Accepted writes a 202 JSON response.

func BadRequest

func BadRequest(w http.ResponseWriter, data any)

BadRequest writes a 400 JSON response.

func Conflict

func Conflict(w http.ResponseWriter, data any)

Conflict writes a 409 JSON response.

func Created

func Created(w http.ResponseWriter, data any)

Created writes a 201 JSON response.

func DecodeJSON

func DecodeJSON[T any](r *http.Request) (T, error)

DecodeJSON decodes the JSON request body into T. Returns an error if the body is missing, malformed, or cannot be decoded.

func Error

func Error(w http.ResponseWriter, statusCode int, code, message string)

Error writes a JSON error response with the given status code, error code, and message.

func Forbidden

func Forbidden(w http.ResponseWriter, data any)

Forbidden writes a 403 JSON response.

func HandleErr

func HandleErr(w http.ResponseWriter, r *http.Request, err error, extraCodes map[string]int)

HandleErr maps an error to an HTTP status code and writes a structured JSON response. extraCodes extends or overrides the default code→status mapping for app-specific error codes. Pass nil if no custom codes are needed.

func HandleValidationError

func HandleValidationError(w http.ResponseWriter, r *http.Request, loc Location, ve *validator.ValidationError)

HandleValidationError writes a 422 JSON response for a ValidationError, tagging every field error with the given request location (body, query, path, or header). The trace_id is populated from the active OTEL span when present.

func InternalServerError

func InternalServerError(w http.ResponseWriter, data any)

InternalServerError writes a 500 JSON response.

func IsJSONDecodeError

func IsJSONDecodeError(err error) bool

IsJSONDecodeError reports whether err originated from JSON decoding: syntax errors, type mismatches, or an empty/truncated body.

func NoContent

func NoContent(w http.ResponseWriter)

NoContent writes a 204 response with no body.

func NotFound

func NotFound(w http.ResponseWriter, data any)

NotFound writes a 404 JSON response.

func Ok

func Ok(w http.ResponseWriter, data any)

Ok writes a 200 JSON response.

func ParseCursorPager

func ParseCursorPager(r *http.Request, opts ...pagination.CursorOption) (pagination.CursorPager, error)

ParseCursorPager parses ?cursor and ?limit query parameters into a [pagination.CursorPager]. Invalid or absent values fall back to package defaults. Pass [pagination.WithDefaultLimit] or [pagination.WithMaxLimit] to override bounds.

?cursor=xxx&limit=20  →  CursorPager{Cursor:"xxx", Limit:20}

func ParseOffsetPager

func ParseOffsetPager(r *http.Request, opts ...pagination.OffsetOption) (pagination.OffsetPager, error)

ParseOffsetPager parses ?page and ?page_size query parameters into a [pagination.OffsetPager]. Invalid or absent values fall back to package defaults. Pass [pagination.WithDefaultPageSize] or [pagination.WithMaxPageSize] to override bounds.

?page=2&page_size=50  →  OffsetPager{Page:2, PageSize:50}

func ParseSort

func ParseSort(r *http.Request, allowed map[string]string) (sorting.Sorts, error)

ParseSort parses the ?sort query parameter into a [sorting.Sorts] slice.

Format: comma-separated field names; prefix "-" for descending order.

?sort=-created_at,name  →  ORDER BY created_at DESC, full_name ASC

allowed maps API field names to domain field names, e.g.:

map[string]string{"createdAt": "created_at", "name": "full_name"}

Returns nil, nil when the parameter is absent. Returns an error for unknown fields or invalid input.

func Response

func Response(w http.ResponseWriter, statusCode int, data any)

Response writes a JSON response with the given status code.

func TooManyRequests

func TooManyRequests(w http.ResponseWriter, data any)

TooManyRequests writes a 429 JSON response.

func Unauthorized

func Unauthorized(w http.ResponseWriter, data any)

Unauthorized writes a 401 JSON response.

func UnprocessableEntity

func UnprocessableEntity(w http.ResponseWriter, data any)

UnprocessableEntity writes a 422 JSON response.

type ErrorResponse

ErrorResponse is the base error response body shape.

type ErrorResponse struct {
    Code    string `json:"code"`
    Message string `json:"message"`
    Details string `json:"details,omitempty"`
    TraceID string `json:"trace_id,omitempty"`
}

type FieldErrorResponse

FieldErrorResponse describes a single field-level validation error in an HTTP response.

type FieldErrorResponse struct {
    Location string         `json:"location,omitempty"`
    Field    string         `json:"field"`
    Code     string         `json:"code"`
    Message  string         `json:"message"`
    Params   map[string]any `json:"params,omitempty"`
}

type Location

Location identifies where in an HTTP request a field error originated. Values mirror the OpenAPI "in" vocabulary.

type Location string

const (
    LocationBody   Location = "body"
    LocationQuery  Location = "query"
    LocationPath   Location = "path"
    LocationHeader Location = "header"
)

type ValidationErrorResponse

ValidationErrorResponse is used for 422 responses; Errors is always a non-nil array.

type ValidationErrorResponse struct {
    ErrorResponse
    Errors []FieldErrorResponse `json:"errors"`
}

Generated by gomarkdoc

Documentation

Overview

Package httpapi provides helpers for building JSON HTTP APIs.

It covers request decoding, structured error responses, and response writing. Error handling maps errs.Error domain errors to HTTP status codes and structured JSON bodies without leaking internal details to clients.

Request decoding

body, err := httpapi.DecodeJSON[CreateUserRequest](r)
if err != nil {
	httpapi.HandleErr(w, r, err, nil)
	return
}

Error handling

HandleErr maps any error to a JSON response. It understands errs.Error values extracted from the chain, JSON decode errors, and falls back to 500 for unknown errors. App-specific error codes are supported via extraCodes:

var appCodes = map[string]int{
	"payment_failed": http.StatusPaymentRequired,
}

httpapi.HandleErr(w, r, err, appCodes)

For validator.ValidationError from request validation, use HandleValidationError to tag each field error with its request location (body, query, path, header):

httpapi.HandleValidationError(w, r, httpapi.LocationBody, ve)

Response writing

httpapi.Ok(w, data)         // 200
httpapi.Created(w, data)    // 201
httpapi.NoContent(w)        // 204

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Accepted

func Accepted(w http.ResponseWriter, data any)

Accepted writes a 202 JSON response.

func BadRequest

func BadRequest(w http.ResponseWriter, data any)

BadRequest writes a 400 JSON response.

func Conflict

func Conflict(w http.ResponseWriter, data any)

Conflict writes a 409 JSON response.

func Created

func Created(w http.ResponseWriter, data any)

Created writes a 201 JSON response.

func DecodeJSON

func DecodeJSON[T any](r *http.Request) (T, error)

DecodeJSON decodes the JSON request body into T. Returns an error if the body is missing, malformed, or cannot be decoded.

func Error

func Error(w http.ResponseWriter, statusCode int, code, message string)

Error writes a JSON error response with the given status code, error code, and message.

func Forbidden

func Forbidden(w http.ResponseWriter, data any)

Forbidden writes a 403 JSON response.

func HandleErr

func HandleErr(w http.ResponseWriter, r *http.Request, err error, extraCodes map[string]int)

HandleErr maps an error to an HTTP status code and writes a structured JSON response. extraCodes extends or overrides the default code→status mapping for app-specific error codes. Pass nil if no custom codes are needed.

func HandleValidationError

func HandleValidationError(
	w http.ResponseWriter,
	r *http.Request,
	loc Location,
	ve *validator.ValidationError,
)

HandleValidationError writes a 422 JSON response for a ValidationError, tagging every field error with the given request location (body, query, path, or header). The trace_id is populated from the active OTEL span when present.

func InternalServerError

func InternalServerError(w http.ResponseWriter, data any)

InternalServerError writes a 500 JSON response.

func IsJSONDecodeError

func IsJSONDecodeError(err error) bool

IsJSONDecodeError reports whether err originated from JSON decoding: syntax errors, type mismatches, or an empty/truncated body.

func NoContent

func NoContent(w http.ResponseWriter)

NoContent writes a 204 response with no body.

func NotFound

func NotFound(w http.ResponseWriter, data any)

NotFound writes a 404 JSON response.

func Ok

func Ok(w http.ResponseWriter, data any)

Ok writes a 200 JSON response.

func ParseCursorPager

func ParseCursorPager(r *http.Request, opts ...pagination.CursorOption) (pagination.CursorPager, error)

ParseCursorPager parses ?cursor and ?limit query parameters into a pagination.CursorPager. Invalid or absent values fall back to package defaults. Pass pagination.WithDefaultLimit or pagination.WithMaxLimit to override bounds.

?cursor=xxx&limit=20  →  CursorPager{Cursor:"xxx", Limit:20}

func ParseOffsetPager

func ParseOffsetPager(r *http.Request, opts ...pagination.OffsetOption) (pagination.OffsetPager, error)

ParseOffsetPager parses ?page and ?page_size query parameters into a pagination.OffsetPager. Invalid or absent values fall back to package defaults. Pass pagination.WithDefaultPageSize or pagination.WithMaxPageSize to override bounds.

?page=2&page_size=50  →  OffsetPager{Page:2, PageSize:50}

func ParseSort

func ParseSort(r *http.Request, allowed map[string]string) (sorting.Sorts, error)

ParseSort parses the ?sort query parameter into a sorting.Sorts slice.

Format: comma-separated field names; prefix "-" for descending order.

?sort=-created_at,name  →  ORDER BY created_at DESC, full_name ASC

allowed maps API field names to domain field names, e.g.:

map[string]string{"createdAt": "created_at", "name": "full_name"}

Returns nil, nil when the parameter is absent. Returns an error for unknown fields or invalid input.

func Response

func Response(w http.ResponseWriter, statusCode int, data any)

Response writes a JSON response with the given status code.

func TooManyRequests

func TooManyRequests(w http.ResponseWriter, data any)

TooManyRequests writes a 429 JSON response.

func Unauthorized

func Unauthorized(w http.ResponseWriter, data any)

Unauthorized writes a 401 JSON response.

func UnprocessableEntity

func UnprocessableEntity(w http.ResponseWriter, data any)

UnprocessableEntity writes a 422 JSON response.

Types

type ErrorResponse

type ErrorResponse struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Details string `json:"details,omitempty"`
	TraceID string `json:"trace_id,omitempty"`
}

ErrorResponse is the base error response body shape.

type FieldErrorResponse

type FieldErrorResponse struct {
	Location string         `json:"location,omitempty"`
	Field    string         `json:"field"`
	Code     string         `json:"code"`
	Message  string         `json:"message"`
	Params   map[string]any `json:"params,omitempty"`
}

FieldErrorResponse describes a single field-level validation error in an HTTP response.

type Location

type Location string

Location identifies where in an HTTP request a field error originated. Values mirror the OpenAPI "in" vocabulary.

const (
	LocationBody   Location = "body"
	LocationQuery  Location = "query"
	LocationPath   Location = "path"
	LocationHeader Location = "header"
)

type ValidationErrorResponse

type ValidationErrorResponse struct {
	ErrorResponse
	Errors []FieldErrorResponse `json:"errors"`
}

ValidationErrorResponse is used for 422 responses; Errors is always a non-nil array.

Directories

Path Synopsis
Package httpapitest provides test helpers for the httpapi package.
Package httpapitest provides test helpers for the httpapi package.

Jump to

Keyboard shortcuts

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