Turn a JSON response into Go structs with json tags.

Conversion runs in your browser. Your API responses — often containing tokens — never leave the device. How to verify this yourself.

Ready
JSON input 0 lines
Go structs 0 structs
 
—

Why hand-written struct tags drift, and what this generator does differently

Paste a JSON document and this page writes the Go struct definitions that would decode it. Everything runs in the tab — the JSON is read by the browser's own parser and the Go source is assembled as text. There is no upload and no account. The rest of this page is about the four details that decide whether the generated code actually works against the API you copied, because a struct that compiles is not the same as a struct that decodes.

The json tag is the part that matters, and hand-written tags drift

A struct tag tells Go which JSON key a field belongs to. If the tag is wrong the field silently stays at its zero value: no error, no warning, just an empty string where you expected a customer name. Go's decoder matches a key to a field in two ways — an exact tag match, then a case-insensitive match against the field name. The trap is that the comparison ignores letter case but not separators. A field called UserID will happily decode the key userid or USERID, but it will not decode user_id, because the underscore is a real character. That is exactly why this generator keeps the original key inside the tag, so {"user_id": 1} becomes UserID int64 `json:"user_id"` rather than relying on the field name to match.

The other half of the problem is that tags rot. A field is added on the server, someone renames a key from created to created_at, and the Go client keeps compiling while quietly decoding nothing. Regenerating from a real response and diffing the result is a cheap way to catch that before it reaches production.

omitempty is about zero values, not about optionality

The single most common bug in generated Go clients is a field tagged omitempty that needs to be able to send zero. omitempty only changes encoding: when you marshal the struct, a field holding its zero value — 0, "", false, nil, or an empty slice or map — is dropped from the output. So a request body built from Quantity int `json:"quantity,omitempty"` cannot express "set the quantity to zero": the key disappears, and the server reads it as "leave the quantity alone".

The same tag does nothing at all on the way in. Decoding treats a missing key and a zero-valued key as the same thing, so omitempty cannot tell you whether the field was absent. If you need that distinction, use a pointer (*int64) or json.RawMessage, both of which can represent "absent" as nil. This generator leaves omitempty off by default for precisely this reason, and adds it everywhere only when you tick the box.

int64, float64 and the 2^53 precision boundary

JSON has one number type, and the parser behind almost every language treats it as a 64-bit float. That means a 64-bit integer ID such as a snowflake — 1276898186410434561 — is already imprecise by the time any decoder sees it; the value becomes 1276898186410434600. The generator cannot recover the digits that were lost before it ran, so it does the honest thing instead: whole numbers that fit inside Go's safe integer range become int64, and anything larger becomes float64 rather than pretending an int64 can hold it. For real IDs the robust fix is to keep them as JSON strings and parse them on the server, which is why generated clients for large APIs usually declare ID string `json:"id"`.

Why inconsistent arrays are merged instead of sampled

Many generators look only at the first element of an array, which is how a codebase ends up with a struct that is missing a field that appears in every later element. This one walks every element and merges them. When the same key holds different types in different elements, the types are widened: int64 plus float64 becomes float64, and any other clash — a string in one element and an object in another, or a value that is sometimes null — becomes interface{}. A field that is null in a single sample also becomes interface{}, because null carries no type information. interface{} is not pretty, but it is far better than a struct that silently drops data and panics later on a nil dereference. Press Sample to see an array whose second element is missing a field, and watch the merged struct keep it.

How to verify nothing leaves the device

Open the browser developer tools, switch to the Network panel and clear it. Convert a document here and watch: no request carries your JSON. Turn off your network connection and convert again — the tool is unaffected, because the parser, the type inference and the Go source generation are all in the page you already loaded. The only third-party script on the site is the advertising tag, which is configured not to receive anything you type. The privacy policy lists every script and what it can see.

Common questions

Does this upload my API response anywhere?

No. The JSON is parsed with the browser's own JSON.parse and the struct text is built by the page. You can prove it by opening the browser network panel and converting a document — no request carries your data — or by going offline and converting again, which still works. This matters because API responses routinely carry bearer tokens and customer records.

Why does my field get int64 when my API sometimes returns a decimal?

The generator merges every array element and widens conflicting number types. If one element has 10 and another has 10.5, the merged type becomes float64. If you know the field is always whole, set Numbers to int64, but be aware that Go's int64 cannot represent everything JSON can — see the precision note in the tutorial.

What does omitempty actually do to my struct?

It only affects encoding: when you marshal the struct back to JSON, a field holding its zero value (0, "", false, nil, an empty slice or map) is left out of the output. It has no effect on decoding. That means a field that must be able to send an explicit 0 or "" should never be tagged omitempty, because "zero" and "absent" become indistinguishable.

How are nested objects and a top-level array named?

Each nested object becomes its own struct named after its parent plus the field name, so a profile object inside the root struct becomes Profile AutoGeneratedProfile with a type of its own. If the top level of your JSON is an array, the element shape is used as the template and the file opens with type AutoGenerated []AutoGeneratedItem, which you can rename to whatever your handler expects.