JSON1

JSON1 / JSON to Go

JSON to Go

Generate Go structs with JSON tags from a JSON sample. Optional fields become pointers tagged omitempty, so encoding/json can tell absent from the zero value.

Processed locally
InputJSON
Ready
OutputGo

Converted output appears here as you type.

Good to know

  • Every record in an array is inspected, not just the first, so a field that appears in only some of them is typed as optional rather than required.
  • Identical nested shapes are emitted once and reused, and reserved words are renamed to something legal in this language.

About this tool

Every field in a Go struct needs a tag to map it to a JSON key, which makes hand-writing one for a large payload slow and easy to get subtly wrong. This produces the full set, with the field and tag columns aligned the way gofmt would align them, so it goes into a file without reformatting.

Exported names follow the conventions the linters actually enforce — an id key becomes ID, not Id, and url becomes URL — because a field must be exported for encoding/json to see it at all.

  • int64JSON integers. Explicitly sized rather than int, whose width depends on the platform.
  • float64Fractional numbers. Also what encoding/json gives you for every number when decoding into an interface{}.
  • *int64An optional field, tagged omitempty — a pointer is the only way to distinguish absent from zero.
  • []stringArrays. A nil slice and an empty one both marshal as [] with omitempty, and as null without it.
  • interface{}A field with no observable type.
Why are some fields pointers?
Because encoding/json cannot otherwise tell a field that was absent from one that arrived as the zero value. A missing count and a count of 0 both leave an int64 holding 0. The pointer plus omitempty is the standard workaround, and it is the reason a generated Go struct looks noisier than the equivalent in a language with an option type.
Why interface{} instead of any?
any is a type alias for interface{} added in Go 1.18 — identical to the compiler, purely a spelling. The output uses the older form because it also compiles on earlier toolchains, and a struct definition is a bad place for a build to break over syntax.
Why is omitempty only on the pointer fields?
Because on a value field it is a footgun: omitempty on a plain int64 drops a real 0 from the encoded output, and on a string it drops a real empty string. It means "omit when this is the zero value", which is only the same as "omit when absent" if the field is a pointer.
Will large integers survive a round trip?
In this struct, yes — int64 holds anything JSON can express as an integer. The failure case is decoding into an interface{} or a map[string]interface{}, where every number becomes float64 and integers above 2^53 lose precision silently. Using the generated struct is how you avoid that.
How are optional fields decided?
Every record in an array is inspected, not just the first. A field that appears in some records and not others is typed as optional, and a value that is sometimes null widens accordingly. Generators that read only the first element get this wrong on exactly the payloads where it matters.
What happens to a key that is a reserved word?
It is renamed to something legal in the target language, and where the language supports it, an annotation records the original JSON key so serialisation still round-trips.