Gorilla Schema

Gorilla Schema fills Go structs from HTTP form values and encodes them back into url.Values using struct tags.

Library
Go
vv1.4.1
1,509stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
45/100Fair
Development Activity0
Maintenance20
Community72
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture78
Code Quality85
Innovation72
Learning Curve55

Gorilla Schema is a small, dependency-free Go library that converts between map[string][]string (the shape of url.Values, r.PostForm, and r.MultipartForm) and Go structs. Instead of hand-writing form-parsing boilerplate in every HTTP handler, you instantiate a single Decoder (or Encoder) and reuse it across requests — it caches struct metadata internally so repeated calls avoid re-walking reflection on every request.

The library supports custom field names and exclusions via a schema struct tag, required-field validation, per-field default values, dotted-path notation for nested structs (Phone.Number), indexed notation for slices of structs (Phones.0.Label), and a RegisterConverter/RegisterEncoder extension point for custom types that don’t implement encoding.TextUnmarshaler. It’s part of the Gorilla web toolkit, the same family as gorilla/mux and gorilla/websocket, and is commonly paired with net/http handlers that need to decode form submissions into typed structs without pulling in a full validation framework.

What You Get

  • A Decoder type that fills a struct from map[string][]string via Decode(dst, src), safe to share as a package-level singleton
  • A symmetric Encoder type that converts a struct back into map[string][]string via Encode(src, dst)
  • Struct-tag driven field mapping (schema:"name"), field exclusion (schema:"-"), required-field enforcement, and default values via schema:"field,default:value"
  • Dotted-path and indexed notation for decoding/encoding nested structs and slices of structs directly from flat form keys
  • RegisterConverter/RegisterEncoder hooks for wiring in custom types beyond the built-in bool/int/float/string/uint variants
  • Typed, structured errors (MultiError, ConversionError, UnknownKeyError, EmptyFieldError) instead of opaque strings

Common Use Cases

  • Decoding r.PostForm/r.MultipartForm from a net/http handler directly into a typed request struct
  • Populating query-parameter structs from r.URL.Query() in REST-style Go APIs
  • Round-tripping structs to url.Values when building outbound HTTP client requests
  • Validating required form fields without adopting a separate validation library

Under The Hood

Architecture The library is a single flat schema package split into four files with no framework or DI layer: cache.go maintains a sync.RWMutex-guarded map[reflect.Type]*structInfo that stores each struct’s field aliases, required/default tag options, and any registered converter, built once per type and reused across every subsequent Decode/Encode call; decoder.go and encoder.go are deliberately symmetric — Decoder.Decode walks the incoming map’s keys, resolves each dotted/indexed path via cache.parsePath into a chain of reflect.Value field lookups (recursing for slices of structs, disambiguated by a numeric path segment), and falls back through encoding.TextUnmarshaler then the built-in converters in converter.go, while Encoder.Encode walks a struct’s fields via reflection and rebuilds the same flat map shape, recursing into embedded and nested structs. The riskiest shared surface is cache.parsePath/cache.create, since every decode and encode call depends on it being correct for arbitrary struct shapes.

Tech Stack Zero external dependencies — go.mod declares only the module path and go 1.20; everything is built on reflect, encoding, strconv, strings, sync, errors, and fmt from the standard library. It has no database or web-framework integration of its own; it’s designed to sit inside net/http handlers and works directly against url.Values-shaped maps such as r.PostForm.

Code Quality Testing is extensive for the library’s size — 54 test functions in decoder_test.go and 14 in encoder_test.go using table-driven testing patterns, run via the Makefile’s test target with -race -cover -coverprofile=... -covermode=atomic. A dedicated GitHub Actions “Security” workflow runs gosec and govulncheck on every push and pull request across Go 1.20 and 1.21, and the Makefile wires up golangci-lint for local/CI linting. Errors are typed and structured (MultiError, ConversionError, UnknownKeyError, EmptyFieldError) rather than ad hoc strings, and naming follows idiomatic Go conventions throughout.

API Design The public surface is two symmetric, single-purpose types — NewDecoder()/Decode() and NewEncoder()/Encode() — mirroring the ergonomics of encoding/json’s Marshal/Unmarshal and requiring no boilerplate beyond instantiating one shared instance per struct type. The same schema struct tag covers naming, exclusion, required fields, and defaults, and the dotted/indexed path convention for nested structs and slices is a well-documented, deliberate solution to a real gap: the standard library has no built-in way to decode form values into typed structs.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search