
Filtering and Sorting in Go APIs Without SQL Injection
Build filter and sort parameters for a Go API from an allowlist: bound values, mapped columns, escaped LIKE wildcards and a blind injection through ORDER BY.
Tag
17 articles

Build filter and sort parameters for a Go API from an allowlist: bound values, mapped columns, escaped LIKE wildcards and a blind injection through ORDER BY.

Compare code-first and spec-first OpenAPI in Go with working code: huma generating the spec from types, and kin-openapi catching bad requests and drift.

Return Go API errors as RFC 9457 problem documents: a Problem type with extensions, one table mapping errors to statuses, and a 500 that leaks nothing.

Decode request JSON strictly in Go: DisallowUnknownFields, a single-value check, body limits and a map from decoder errors to 400, 413 and 422 answers.

Implement PATCH in a Go API with merge-patch semantics: tell absent, null and zero apart, apply only the keys sent and reject bad patches before any SQL runs.

Paginate a Go API with offset, keyset and signed cursors on SQLite: duplicates under inserts, rows lost on tied keys, and 7.9 ms against 31 µs at depth.

Serve a 200,000-row JSON export in Go by streaming rows from the database: first byte in 1 ms instead of 161, 1 MB of heap instead of 57, and gzip on the fly.

How a Go API should wrap its JSON: bare resources, a data envelope for lists, empty arrays instead of null, optional totals, and why to skip a success flag.

Write JSON marshalers in Go for enums, dates, durations and Unix times: MarshalText versus MarshalJSON, clear errors, the pointer receiver trap and recursion.

Make POST safe to retry in a Go API with an Idempotency-Key middleware: concurrent duplicates, replayed responses, payload fingerprints and 5xx handling.

Use go-playground/validator in a Go API: tags, nested rules, JSON field names in errors, and the traps around zero values, dive, panics and per-call setup.

Stream JSON in Go without loading it all: an iterator over a top-level array, NDJSON with a Decoder, element-by-element encoding and a live heap of 0.02 MB.