Why Generate Swift Codable Structs from JSON?
Every iOS and macOS app that communicates with a backend API needs to decode JSON responses into native Swift types. Writing these model structs by hand is tedious, error-prone, and time-consuming, especially for large or deeply nested payloads. A code generator eliminates typos, ensures consistent type mapping, and lets you start building features immediately.
Swift's Codable protocol, introduced in Swift 4, provides compiler-synthesized encoding and decoding when your property names and types match the JSON keys. When they don't match, you need a CodingKeys enum to bridge the gap. This tool handles both cases so you can paste raw API JSON and get a compilable Swift file in seconds.
How JSON Types Map to Swift Types
- • JSON string →
String - • JSON integer →
Int - • JSON float →
Double - • JSON boolean →
Bool - • JSON null →
String?
- • JSON object → nested
struct - • JSON array of strings →
[String] - • JSON array of objects →
[StructName] - • Mixed arrays →
[Any]
Understanding CodingKeys
Swift naming conventions use camelCase for properties, but many APIs return snake_case keys. When the JSON key doesn't match the Swift property name, the Codable synthesizer can't automatically map them. That's where CodingKeys comes in: a nested enum that pairs each property with its JSON key string.
"user_name" → Swift userName "created_at" → Swift createdAt
Alternatively, you can set decoder.keyDecodingStrategy = .convertFromSnakeCase on your JSONDecoder to handle the conversion globally without CodingKeys. However, CodingKeys gives you finer control and works for any key format, not just snake_case.
Best Practices for Swift Codable Models
- 1
Use structs, not classes. Value types are safer for data models. They provide implicit copying, are thread-safe by default, and the compiler can optimize them more aggressively.
- 2
Prefer let over var. Immutable properties prevent accidental mutations. Use var only when a property genuinely needs to change after initialization or when it is optional.
- 3
Make nullable fields Optional. If an API can return null for a field, model it as Optional in Swift. This lets the decoder gracefully handle missing values instead of throwing an error.
- 4
Handle dates with dateDecodingStrategy. Set
.iso8601or a custom DateFormatter on your JSONDecoder rather than decoding dates as raw strings. - 5
Write unit tests for decoding. Include sample JSON responses in your test bundle and verify that your models decode correctly. This catches API changes before they hit production.
Frequently Asked Questions
What is Swift Codable?
Codable is a Swift protocol (a typealias for Encodable and Decodable) that lets you convert between Swift types and external formats like JSON. By conforming a struct to Codable, the compiler automatically synthesizes encoding and decoding logic, eliminating manual serialization code.
When do I need CodingKeys in Swift?
You need a CodingKeys enum when the JSON key names differ from your Swift property names. For example, if the JSON uses snake_case like "user_name" but your Swift property is camelCase "userName", CodingKeys bridges the gap. You can also use JSONDecoder's keyDecodingStrategy as an alternative for snake_case conversion.
How does this tool handle nested JSON objects?
Each nested JSON object is converted into a separate Swift struct. The parent struct references the child struct as a property type. For instance, a JSON with an "address" object produces both a Root struct and an Address struct, with Root containing a property of type Address.
What is the difference between let and var in the generated structs?
The generated code uses "let" for non-optional properties that must always have a value, and "var" for optional properties that can be null. Optional properties use Swift's Optional type (Type?) and default to nil if the key is absent from the JSON response.
Can I decode a JSON array at the root level?
Yes. If your root JSON is an array of objects, the tool generates a struct for the array element type. You then decode using [StructName].self instead of StructName.self. The generated code includes a usage comment showing the correct JSONDecoder call for root-level arrays.