Working with JSON in Swift: Parsing and Serialization
JSON (JavaScript Object Notation) is a lightweight data interchange format widely used in web services and mobile applications. In the Apple ecosystem (iOS, macOS, watchOS, tvOS), working with JSON is an integral part of development: from loading data from a server to saving application settings. In this article, we will take a detailed look at how to perform parsing (decoding) and serialization (encoding) of JSON in Swift using the built-in Codable, JSONDecoder, and JSONEncoder protocols.
1. Codable Basics: Data Model
The modern approach to working with JSON in Swift is based on the Codable protocol, which combines two protocols: Encodable (for serialization) and Decodable (for parsing). For your structure or class to be convertible to and from JSON, simply declare it as Codable.
Consider an example of a user model:
struct User: Codable { let id: Int let name: String let email: String let isActive: Bool}If the keys in JSON differ from the property names in Swift (for example, snake_case is used instead of camelCase), you can use the CodingKeys enum:
struct User: Codable { let id: Int let fullName: String let email: String let isActive: Bool
enum CodingKeys: String, CodingKey { case id case fullName = "full_name" case email case isActive = "is_active" }}2. Parsing JSON with JSONDecoder
To convert a JSON string or data into Swift objects, JSONDecoder is used. The main method is decode(_:from:), which takes a data type (conforming to Decodable) and a Data object.
Example of parsing a JSON string received from an API:
let jsonString = """{ "id": 1, "name": "Ivan Petrov", "email": "ivan@example.com", "is_active": true}"""
let jsonData = Data(jsonString.utf8)
do { let decoder = JSONDecoder() let user = try decoder.decode(User.self, from: jsonData) print("User: \\(user.name), email: \\(user.email)")} catch { print("Decoding error: \\(error.localizedDescription)")}Often JSON comes as an array of objects. In this case, simply specify the type [User].self:
let jsonArrayString = """[ {"id": 1, "name": "Ivan", "email": "ivan@test.com", "is_active": true}, {"id": 2, "name": "Maria", "email": "maria@test.com", "is_active": false}]"""
let jsonArrayData = Data(jsonArrayString.utf8)
do { let users = try JSONDecoder().decode([User].self, from: jsonArrayData) users.forEach { print($0.name) }} catch { print("Error: \\(error)")}3. Serializing Objects to JSON with JSONEncoder
The reverse process — converting a Swift object to JSON — is performed using JSONEncoder. The encode(_:) method returns a Data object, which can then be converted to a string or sent to a server.
let user = User(id: 3, fullName: "Alexey Smirnov", email: "alex@example.com", isActive: true)
do { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted // for readable formatting let jsonData = try encoder.encode(user) if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }} catch { print("Encoding error: \\(error)")}The output will look like this:
{ "id" : 3, "full_name" : "Alexey Smirnov", "email" : "alex@example.com", "is_active" : true}Note that JSO