go 20 lines · 1 tab

Streaming JSON decoding with DisallowUnknownFields

Leah Thompson Jan 2026
1 tab
package api

import (
  "encoding/json"
  "errors"
  "io"
)

func decodeJSON(r io.Reader, dst any) error {
  dec := json.NewDecoder(r)
  dec.DisallowUnknownFields()

  if err := dec.Decode(dst); err != nil {
    return err
  }
  if err := dec.Decode(&struct{}{}); err != io.EOF {
    return errors.New("body must contain a single JSON value")
  }
  return nil
}
1 file · go Explain with highlit

Large request bodies are where naive code falls over. Instead of io.ReadAll, I decode JSON incrementally with json.Decoder and enable DisallowUnknownFields so unexpected fields fail fast. That becomes a surprisingly strong safety net when you evolve APIs: client typos and version drift surface as clear 400s instead of becoming silently ignored data. I also guard against multiple JSON values by attempting a second decode and expecting io.EOF. Combined with http.MaxBytesReader, this prevents memory blowups and a class of parsing ambiguities. It's a small helper, but it pushes validation into a single choke point so handlers can stay focused on business logic.


Related snips

Share this code

Here's the card — post it anywhere.

Streaming JSON decoding with DisallowUnknownFields — share card
Link copied