Guide
Swift Codable structs from an API response
Swift’s Codable turns JSON into typed values with a single call, but only once you have written structs that match the data exactly — every key, every optional, every nested type. This generator writes them from a sample, including the CodingKeys that map Swift-style names onto snake_case or hyphenated keys.
How Codable decoding works
A type that conforms to Codable can be created by JSONDecoder: let user = try JSONDecoder().decode(User.self, from: data). Swift synthesises the decoding code from the stored properties, so the property names, types and optionality must match the JSON. If they do not, decoding throws a DecodingError that names the key path, which is far more useful than a crash later.
CodingKeys only where needed
Swift style is camelCase, so order_id becomes orderId. Codable needs to know about that difference, and the generator writes a CodingKeys enum mapping each property to its key — but only in structs where some key actually differs, keeping simple structs short. If every key in your API is snake_case, you can delete the enums and set decoder.keyDecodingStrategy = .convertFromSnakeCase instead; hyphenated keys still need explicit keys.
Optionals
Keys missing from some samples and values that were sometimes null become optionals, such as let coupon: String?. Synthesised decoding treats a missing key and a null value the same for optionals, so either case decodes to nil. Non-optional properties make decoding fail when the key is missing, which is what you want for fields your app cannot work without.
Mixed types and JSONValue
Swift has no built-in “any JSON” type. When a field was always null or had different types in different samples, the generator uses JSONValue, a small enum that decodes strings, numbers, booleans, arrays, objects and null, and appends its implementation to the output. Switch over it to read the value once you know what it contains.
Dates
With date types on, ISO 8601 timestamps become Date, and a comment reminds you to set decoder.dateDecodingStrategy = .iso8601. Fractional seconds need a custom formatter, because the built-in ISO 8601 strategy rejects them.
A worked example
The sample user produces User, Order, Item and Address. Order gets a CodingKeys enum with case orderId = "order_id", its coupon is String?, and because the address’s unit is null in the sample, the output includes the JSONValue helper for it.
Using the models
With async URLSession: let (data, _) = try await URLSession.shared.data(from: url) then decode. In SwiftUI, load the value in a .task modifier and store it in @State; Equatable conformance lets SwiftUI avoid redundant redraws.
Root arrays and wrapped responses
When the JSON is an array, the root struct describes one element; decode with [User].self. When results are wrapped, as in { "data": [...], "meta": {...} }, paste the whole response: the wrapper becomes the root struct and the inner objects get their own, so paging metadata is decoded too.
Keeping models in sync
APIs change. Keep a sample response in your test bundle and decode it in a unit test; when the provider renames a key or changes a type, the failing test points to the exact key path long before users see a broken screen.
Related tools
Create the Android models with JSON to Kotlin, Flutter classes with JSON to Dart, web types with JSON to TypeScript, or format the sample with the JSON Formatter.
Checked against the current version of the JSON to Swift Codable on .

