Codable and JSON
Prerequisites: Structs, Error handling
JSON is the most common format for sending data between programs —
every web API speaks it. Swift converts between JSON and your own types
with the Codable protocol, and the compiler writes the conversion
code for you.
Encoding: Swift → JSON
import Foundation
struct User: Codable {
let name: String
let age: Int
let tags: [String]
}
let user = User(name: "Ada", age: 36, tags: ["admin", "beta"])
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
let data = try encoder.encode(user)
print(String(decoding: data, as: UTF8.self))
{"age":36,"name":"Ada","tags":["admin","beta"]}
.sortedKeys makes the key order predictable; add .prettyPrinted
for indented, human-readable output.
Decoding: JSON → Swift
import Foundation
struct User: Codable {
let name: String
let age: Int
let email: String?
}
let json = """
{"name": "Ada", "age": 36}
"""
do {
let user = try JSONDecoder().decode(User.self, from: Data(json.utf8))
print(user.name, user.age, user.email ?? "no email")
} catch {
print("Invalid JSON: \(error)")
}
Ada 36 no email
- Decoding can fail (bad JSON, missing or wrongly-typed fields), so it
throws. - An optional property may be missing from the JSON; a non-optional one must be present.
- Arrays decode with
[User].self.
Different key names
APIs often use snake_case keys. Either let the decoder convert them:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase // "created_at" → createdAt
or map names explicitly with a CodingKeys enum:
struct Product: Codable {
let id: Int
let displayName: String
enum CodingKeys: String, CodingKey {
case id
case displayName = "title"
}
}
Paste a sample API response into the JSON Formatter to see its structure before writing the matching structs.
Common mistakes
- Making a property non-optional when the API sometimes leaves it out —
the whole decode fails with a
keyNotFounderror. - Ignoring the decoding error. Print it: it names the exact key and problem.