marshal

package
v1.0.448 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 21 Imported by: 3

Documentation

Overview

Package marshal provides helpers to write JSON HTTP responses and to decode JSON request bodies, using github.com/ugorji/go/codec.

WriteJSON is the single response path used by porto handlers: it writes errors (anything implementing WriteHTTPResponse, such as httperror.Error) with their own status code, and everything else as a 200 application/json body, gzip-compressed when it is at least 1 KiB and the client accepts gzip, and pretty-printed when the URL has a "?pp" query parameter. Success responses include Vary: Accept-Encoding.

func (s *svc) get(w http.ResponseWriter, r *http.Request, _ restserver.Params) {
	var req ItemRequest
	if marshal.DecodeBody(w, r, &req) != nil {
		return // 400 invalid_json or 413 request_too_large already written
	}
	item, err := s.store.Get(r.Context(), req.ID)
	marshal.WriteJSON(w, r, err, item) // first non-nil value wins
}

Decoding is strict: unknown JSON fields are an error (DecoderHandle). DecodeBody limits request bodies to 10 MiB by default; LimitRequestBody configures a different limit or explicitly disables it with a negative value.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcceptsGzip added in v1.0.448

func AcceptsGzip(h http.Header) bool

AcceptsGzip reports whether Accept-Encoding permits gzip, considering all header lines and quality values. An explicit gzip entry overrides a wildcard; malformed or out-of-range quality values are treated as a refusal.

func Decode

func Decode(r io.Reader, result any) error

Decode reads JSON from r and decodes it into result using DecoderHandle. The reader is not size-limited; wrap request bodies with http.MaxBytesReader first.

func DecodeBody

func DecodeBody(w http.ResponseWriter, r *http.Request, result any) error

DecodeBody decodes the JSON request body into result. On failure it writes a 400 invalid_json response, or 413 request_too_large on overflow, and returns the error, so callers can simply return. A known oversized Content-Length is rejected before any byte is read. The default limit is limits.DefaultMaxRequestBody; LimitRequestBody overrides it. After a successful decode, the remaining body is consumed within the limit so trailing bytes cannot bypass the size check; with the limit disabled it is left unread. Decode and DecodeBytes remain unbounded.

func DecodeBytes

func DecodeBytes(data []byte, result any) error

DecodeBytes decodes JSON data into result using DecoderHandle (strict: unknown fields are an error).

func DecoderHandle

func DecoderHandle() *codec.JsonHandle

DecoderHandle returns the codec handle used for decoding JSON into Go types. It errors when a JSON field has no matching Go field, and decodes untyped objects into map[string]any. The returned handle is shared and must not be mutated by callers.

func EncodeBytes

func EncodeBytes(printSetting PrettyPrintSetting, value any) ([]byte, error)

EncodeBytes encodes value to JSON with the given pretty-print setting and returns the bytes.

func LimitRequestBody added in v1.0.438

func LimitRequestBody(next http.Handler, maxBytes int64) http.Handler

LimitRequestBody bounds reads from request bodies. Zero selects limits.DefaultMaxRequestBody; a negative value disables the limit. It writes no response itself, so it can wrap CORS, correlation, logging and metrics middleware without bypassing them: a body whose known Content-Length exceeds the limit fails on its first read with *http.MaxBytesError without reading any bytes, and other bodies fail once they exceed the limit. DecodeBody honors this policy and writes HTTP 413; other body readers must handle *http.MaxBytesError themselves.

func NewEncoder

func NewEncoder(w io.Writer, r *http.Request) *codec.Encoder

NewEncoder returns a JSON encoder writing to w, pretty-printing when the request URL has a "pp" query parameter. r must not be nil.

func NewRequest

func NewRequest(method string, url string, req any) (*http.Request, error)

NewRequest builds an http.Request whose body is req: an io.Reader, []byte or string is sent as is, anything else is JSON-encoded with encoding/json. No Content-Type header is set.

func WriteJSON

func WriteJSON(w http.ResponseWriter, r *http.Request, bodies ...any)

WriteJSON serialises the first non-nil body value as the HTTP response. A value implementing WriteHTTPResponse writes itself (httperror values set their own status); any other error is converted with httperror.NewFromPb (500 unexpected unless it carries a gRPC status) and written the same way, except that a converted error with a 5xx status is sent with the generic http.StatusText message while its text is only logged; errors other than 404 are also logged with the caller's file and line. Anything else is written as application/json with status 200, gzip-compressed for payloads of at least 1 KiB when the request accepts gzip, and pretty-printed when the URL has a "pp" query parameter. Success responses vary by Accept-Encoding. Encoding and write failures are logged, not reported. r must not be nil.

Passing several values lets a handler write either the error or the result in one call:

x, err := doSomething()
marshal.WriteJSON(w, r, err, x)

func WritePlainJSON

func WritePlainJSON(w http.ResponseWriter, statusCode int, body any, printSetting PrettyPrintSetting)

WritePlainJSON writes body as application/json with the given status code and pretty-print setting, without gzip, error handling or logging.

Types

type PrettyPrintSetting

type PrettyPrintSetting int

PrettyPrintSetting controls how to format json when encoding a go type -> json

const (
	// DontPrettyPrint the output has no additional space/line breaks, and has random ordering of map keys
	DontPrettyPrint PrettyPrintSetting = 0

	// PrettyPrint provides an output more suitable for human consumption, it has line breaks/indenting
	// and map keys are generated in order.
	PrettyPrint PrettyPrintSetting = 1
)

type WriteHTTPResponse

type WriteHTTPResponse interface {
	// WriteHTTPResponse writes the value, including status and headers, to w.
	WriteHTTPResponse(w http.ResponseWriter, r *http.Request)
}

WriteHTTPResponse is implemented by types that take full control over how they are written as an HTTP response (httperror.Error and ManyError do).

Jump to

Keyboard shortcuts

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