Generate Swift Codable structs from a JSON sample — camelCase properties with a CodingKeys enum pinning the wire names wherever a spelling had to change, Optionals where keys come and go or turn null, and a small JSONValue enum appended for the slots the sample cannot settle, so the output still compiles. Free, no sign-up — runs locally in your browser.
Why generate Swift structs from a sample?
Codable's synthesis is wonderful until a key goes missing:
then a decode that worked on every sample you tried throws
in production, because the property you declared
non-optional was absent from the response you never saw.
Swift model code is a set of claims — this key always
exists, it is always a string, its name is camelCase — and
the sample is the only evidence available for those claims
before the app ships. This converter reads the sample the
way a careful reviewer would: objects become
Codable structs, arrays become
[T], absence and null become Optionals,
renames produce a complete CodingKeys enum that pins every wire name, and
the slots no sample could settle become a small
JSONValue enum that is appended, explained,
and ready to compile — not an Any that Swift
would reject.
How to use this tool
- Paste the JSON. A real API response is ideal; include several array elements if you have them, because absence across elements is how Optional properties are discovered.
- Name the root struct.
Root is fine for a quick look; for code you will keep, use the name it will wear in your project. - Press Generate Swift. The root struct comes first, the structs it references after it, and the
JSONValue helper last if it is needed. - Read the notes if any appear. They list every
JSONValue slot, every backticked keyword property and every name collision — nothing was decided silently. - Copy or download the result, then refine it: adjust
CodingKeys where your API's naming has rules a sample cannot show, swap in Date or URL where strings are really those, and let the compiler take it from there.
The rules it follows
Numbers. Whole numbers become
Int; any fraction widens the slot to
Double — a JSON 1.0 is the number
1 to every parser, so a field your API always sends as
2.0 reads as an integer sample unless a real
fraction appears. Names. Structs are
PascalCase after the key that holds them; properties are
camelCase. When a property's spelling differs from its key,
the struct gains a CodingKeys enum listing
every property — renamed ones with their raw value,
others bare — because a partial enum is a trap.
Absence and null. Missing from some
elements or sometimes null → Optional. Null
everywhere or genuinely mixed types → JSONValue,
with the helper enum appended and the slot noted.
Merging. Identical shapes — same keys,
same types — share one struct instead of being emitted
twice.
Worked example
Given this sample (the second user has no nickname, and the keys are already camelCase):
{
"teamName": "Platform",
"users": [
{ "id": 1, "firstName": "Ada", "nickname": "ada" },
{ "id": 2, "firstName": "Grace" }
]
}
the converter emits — no CodingKeys are needed, because no name had to change:
struct Root: Codable {
let teamName: String
let users: [User]
}
struct User: Codable {
let id: Int
let firstName: String
let nickname: String?
}
The String? is the second user talking: a
non-optional nickname would make
JSONDecoder throw on exactly that response.
Had the sample spelled that key first_name,
User would also carry a CodingKeys
enum listing all three properties, with
case firstName = "first_name" pinning the
wire name.
Frequently asked questions
Why do some structs have a CodingKeys enum and others don't?
Swift's synthesized Codable conformance matches property names to JSON keys exactly. When every key in a struct is already spelled the way the camelCase property is — most keys in most APIs — the synthesis is correct as-is and a CodingKeys enum would be pure noise. The moment one property's name differs from its key (a snake_case key, a keyword written in backticks), the struct needs the enum, and it then lists EVERY property, not just the renamed one: a partial CodingKeys enum discards the compiler's synthesis for the unlisted properties too, which fails in ways that eat an afternoon. So the enum appears exactly when it is needed, and complete when it appears.
When does a property become Optional (String? instead of String)?
When the sample shows the value can fail to be there: the key is missing from some elements of an array, or it is present but sometimes null. JSONDecoder is unforgiving here in a way that makes this matter — a non-optional property whose key is absent throws keyNotFound and fails the whole decode, not just that field. Optional turns 'sometimes absent' into a value you can handle, which is the truthful model of what the sample shows.
What is the JSONValue enum at the bottom of some outputs?
The fallback for slots the sample could not settle: a key that is null everywhere (no evidence what it would hold), or one that genuinely mixes types across elements. Swift has no built-in 'any JSON value' type, so rather than emit code that cannot compile, the generator appends a small recursive JSONValue enum — string, int, double, bool, array, object, null — with a working Codable conformance, and types those slots with it. The notes list every slot that uses it and why. If your API stabilises, regenerate with a better sample and the enum disappears.
Why Int for whole numbers and Double for fractions?
Because Codable decodes what the type declares, and the sample distinguishes the two: a slot that only ever shows whole numbers becomes Int, a single fractional sighting makes it Double — Int cannot hold the 2.5 your API demonstrably sends. The mirror trap also applies: JSON 1.0 is the number 1 to every parser, so a field your API always sends as 2.0 samples as an integer here. If a value must survive as a decimal exactly (money), that is a modelling decision for after generation — Decimal is not inferred from spelling.
One property is written in backticks (`class`). Why?
Your JSON has a key that is a Swift keyword. Swift permits keywords as member names in backticks — let `class`: String is legal — and the property's CodingKeys entry pins the wire name without them, so decoding looks for "class" as it should. The notes flag each backticked property. If your style guide forbids them, rename the property and keep its CodingKeys entry, which is doing the real work.
Should the properties be let or var?
The generator emits let, because a decoded model value is a fact about what the API sent, and immutability is the safer default to review from. If your design mutates models in place, changing let to var on the structs you keep is a mechanical pass — Codable does not care either way. What it does care about (names, optionality, the CodingKeys mapping) is the part this tool settles.