How to Read and Write JSON in Swift

Here we will explain how to read and write JSON in Swift.

Convert a JSON String to a Swift Object

Here we'll use JSONDecoder to convert a JSON string into a Swift struct instance.

We'll convert the following JSON string:

{
    "name": "Emma",
    "age": 20,
    "email": "emma@mail.com"
}

Define a struct to hold the JSON data.

To decode using JSONDecoder, the type must conform to the Decodable protocol.

Codable is a type alias for both Decodable and Encodable, so conforming to Codable also works.

Define a Person struct as follows. If the property names don't match the JSON keys, decoding will fail.

struct Person: Decodable {
    var name: String
    var age: Int
    var email: String
}

To convert the JSON string above into Person using JSONDecoder, do the following:

import Foundation

struct Person: Decodable {
    var name: String
    var age: Int
    var email: String
}

let jsonData = """
{
    "name": "Emma",
    "age": 20,
    "email": "emma@mail.com"
}
""".data(using: .utf8)!

let person = try JSONDecoder().decode(Person.self, from: jsonData)

print(person.name)
print(person.age)
print(person.email)

The output will be as follows, showing that the JSON was converted into a person object:

Emma
20
emma@mail.com

Convert a JSON String to a Swift Object with Extra Properties

Earlier we defined a struct whose properties matched the JSON exactly, but you may want to add additional properties to the struct.

If you simply add properties that don't exist in the JSON to the struct above, decoding will fail with an error.


For example, if you add a nickname property to the Person struct and run the code, you'll see an error like this:

Playground execution terminated: An error was thrown and was not caught.

If we dump the error using do-catch, we get the following error.

import Foundation

struct Person: Decodable {
    var name: String
    var age: Int
    var email: String
    var nickname: String
}

let jsonData = """
{
    "name": "Emma",
    "age": 20,
    "email": "emma@mail.com"
}
""".data(using: .utf8)!

do {
    let person = try JSONDecoder().decode(Person.self, from: jsonData)
    print(person.name)
    print(person.age)
    print(person.email)
} catch {
    dump(error)
}
▿ Swift.DecodingError.keyNotFound
  ▿ keyNotFound: (2 elements)
    - .0: CodingKeys(stringValue: "nickname", intValue: nil)
    ▿ .1: Swift.DecodingError.Context
      - codingPath: 0 elements
      - debugDescription: "No value associated with key CodingKeys(stringValue: \"nickname\", intValue: nil) (\"nickname\")."
      - underlyingError: nil

Reading and writing JSON in Swift 1


When you want the Swift type to have properties that aren't present in the JSON, you can avoid errors by giving those additional properties default values and defining CodingKeys to list only the properties that are decoded from the JSON.

import Foundation

struct Person: Decodable {
    var name: String
    var age: Int
    var email: String
    var nickname: String = ""
    
    private enum CodingKeys: String, CodingKey {
        case name, age, email
    }
}

let jsonData = """
{
    "name": "Emma",
    "age": 20,
    "email": "emma@mail.com"
}
""".data(using: .utf8)!

do {
    let person = try JSONDecoder().decode(Person.self, from: jsonData)
    print(person.name)
    print(person.age)
    print(person.email)
} catch {
    dump(error)
}

The result is as follows; decoding succeeds without an error:

Emma
20
emma@mail.com

Reading and writing JSON in Swift 2


Convert a Swift Object to a JSON String

Now let's do the opposite: convert a Swift object into a JSON string.

We'll use JSONEncoder to generate a JSON string from a Swift struct.

To encode using JSONEncoder, the type must conform to the Encodable protocol.

Codable is a type alias for Decodable and Encodable, so conforming to Codable also works.


To generate a JSON string from a Person struct instance, do the following:

import Foundation

struct Person: Encodable {
    var name: String
    var age: Int
    var email: String
    var nickname: String
}

let person = Person(name: "Michael", age: 16, email: "michael@gmail.com", nickname: "Mike")

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let jsonData = try encoder.encode(person)
let jsonString = String(data: jsonData, encoding: .utf8)!

print(jsonString)

The output will look like this, confirming that person was converted to a JSON string:

{
  "age" : 16,
  "name" : "Michael",
  "nickname" : "Mike",
  "email" : "michael@gmail.com"
}

Convert a Swift Object to a JSON String with Selected Properties

If you want to convert only specific properties of a Swift object into a JSON string, define CodingKeys and list only the properties you want to include in the JSON.

For example, if you want to output only name and email from the Person struct, you can do the following:

import Foundation

struct Person: Encodable {
    var name: String
    var age: Int
    var email: String
    var nickname: String
    
    private enum CodingKeys: String, CodingKey {
        case name, email
    }
}

let person = Person(name: "Michael", age: 16, email: "michael@gmail.com", nickname: "Mike")

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let jsonData = try encoder.encode(person)
let jsonString = String(data: jsonData, encoding: .utf8)!

print(jsonString)

The output will be as follows, with only "name" and "email" included in the JSON string:

{
  "name" : "Michael",
  "email" : "michael@gmail.com"
}

Reading and writing JSON in Swift 3

If the type conforms to Codable (not just Encodable), then to satisfy Decodable you need to provide default values for any properties that are not included in CodingKeys.


That wraps up our explanation of how to read and write JSON in Swift.