Codable and JSON

Swift · Practical · 12 min

Almost every app talks to a JSON API, and Codable turns that into a few lines of type-safe code.

Codable is a typealias for Encodable & Decodable. When all stored properties are themselves Codable, the compiler synthesizes the encoding and decoding code — you just declare conformance.

Decode with JSONDecoder().decode(User.self, from: data) and encode with JSONEncoder().encode(value). Both throw on invalid or mismatched data, so they're called with try. The errors (DecodingError.keyNotFound, .typeMismatch...) describe exactly which path failed.

Mapping JSON to Swift:

  • Optional properties may be missing or null; non-optional ones are required.
  • Arrays and nested objects map to arrays and nested Codable types.
  • Rename keys with a nested enum CodingKeys: String, CodingKey { case id, fullName = "full_name" } — every property you want coded must be listed.
  • Or set decoder.keyDecodingStrategy = .convertFromSnakeCase to map full_name to fullName globally.
  • Dates need a strategy, e.g. decoder.dateDecodingStrategy = .iso8601.
  • encoder.outputFormatting = [.prettyPrinted, .sortedKeys] for readable output.

For unusual shapes, implement init(from decoder: Decoder) yourself using a keyed container: let c = try decoder.container(keyedBy: CodingKeys.self) and try c.decodeIfPresent(...).

Enums with raw values are Codable out of the box; enums with associated values get a synthesized keyed format.

Example

import Foundation
struct User: Codable {
    let id: Int
    let fullName: String
    let email: String?
    let roles: [String]
}

let json = Data("""
{"id": 7, "full_name": "Ana Ruiz", "roles": ["admin"]}
""".utf8)

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
    let user = try decoder.decode(User.self, from: json)
    print(user.fullName, user.email as Any)   // Ana Ruiz nil

    let encoder = JSONEncoder()
    encoder.outputFormatting = .sortedKeys
    print(String(decoding: try encoder.encode(user), as: UTF8.self))
    // {"fullName":"Ana Ruiz","id":7,"roles":["admin"]}
} catch {
    print("decode failed:", error)
}

Remember

  • Declare Codable and the compiler writes the coding code
  • Rename keys with CodingKeys or a key strategy
  • Non-optional properties are required in the JSON

Watch out for

  • Declaring a field non-optional when the API sometimes omits it, so the whole decode fails.

Check yourself

  1. A JSON object lacks the key for a non-optional `String` property. What happens on decode?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.apple.com/documentation/foundation/encoding-and-decoding-custom-types

Builds on

Unlocks

Nothing builds on this yet.

Codable and JSON · Swift · Topolearn