Swift and JSON — Introducing the Codable Protocol

Ashok’s Bite Sized Guides — Guide #01

Ashok Khanna
2 min readApr 18, 2022

JSON has become the lingua franca of data transfer across the World Wide Web. In this bite sized guide, we will introduce Swift’s Codable Protocol for encoding and decoding JSON.

Conforming to the Codable Protocol is straightforward:

  • Basic types like STRING, DOUBLE, INT, DATE, DATA or URL automatically conform to Codable
  • Any type whose properties are Codable automatically conforms to Codable just by declaring conformance to the protocol:
struct Coordinate: Codable {
var latitude: Double
var longitude: Double
}
  • Built-in types such as ARRAY, DICTIONARY, and OPTIONAL also conform to Codable whenever they contain codable types
  • Indeed, any custom type can also be Codable as long as all of its properties are Codable
struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: [Coordinate]
}

Once we established the Codable protocol for our types, we can readily encode and decode Swift types to JSON.

Encoding Swift Objects to JSON

Encoding is the easy part. Here is a generic function you can use.

func myEncoder<T: Encodable>(_ data: T) throws -> String {    let encoder = JSONEncoder()    encoder.keyEncodingStrategy = .convertToSnakeCase    let jsonData = try encoder.encode(data)    return String(data: jsonData, encoding: .utf8)!}

Note that Codable is a typealias for the Encodable and Decodable protocols. In the above function, we just need the parameter data to conform to the Encodable protocol (which Codable will also do).

Decoding Swift Objects to JSON

Decoding objects can be just as easy as encoding, but we also have a few extra options to better handle external data being passed into our programs. Antoine van der Lee covers them well in this post.

Lets run through some basic concepts first:

  • Unless you use custom coding keys (refer to the official Apple Documentation), your property names need to match exactly to the keys supplied in the JSON string you are decoding
  • This makes sense given Swift would not know how to otherwise guess how to map JSON data to Swift Objects
  • As JavaScript is typically written in snake_case whilst Swift is written in camelCase, it is very valuable to set the keyEncodingStrategy and keyDecodingStrategy to .convertToSnakeCase (see above in myEncoder) or .convertFromSnakeCase (see below in myDecoder)
  • Any keys in the JSON string that are not defined as properties in your Swift types simply get discarded. This is helpful in that you can update your APIs on the server side without breaking the client code already installed on your users devices (and subsequently requiring an app update to fix).

With all that said, below is an example of a decoder function — it is not too scary! [Actually it does some nice things with protocols and generics, but that’s not related to decoding JSON :)]

func myDecoder<T: Decodable>(_ decodeType: T.Type, _ from: String) throws -> T {   let decoder = JSONDecoder()   decoder.keyDecodingStrategy = .convertFromSnakeCase   let jsonData = from.data(using: .utf8)!   return try decoder.decode(decodeType, from: jsonData)}

Thanks for reading!

--

--

Ashok Khanna

Masters in Quantitative Finance. Writing Computer Science articles and notes on topics that interest me, with a tendency towards writing about Lisp & Swift