本文へスキップ
Hironobu Iga

Codable で CamelCase ⇄ SnakeCase の変換を行う

JSONDecoder の keyDecodingStrategy / keyEncodingStrategy を使い、CodingKey を手書きせずに命名規則の差を吸収する方法です。

公開日

この記事は別サイトにも掲載しています。 https://qiita.com/iganin/items/6c6a588dd73731097698

はじめに

Xcode 9.3 からデフォルトの Swift version が 4.0 から 4.1 へと上がります。 いくつかの改善点がありますが、Codable 周りで役立ちそうな改善がありましたので、メモがてら共有いたします。

以下の記載は 2/20 時点の β 版の情報にもとづき作成しています。 fix 版リリース時には変更になる可能性がありますのでご注意下さい。

CamelCase と SnakeCase

iOS では一般的にプロパティの名称に CamelCase を使用することが多いかと思います。 例えば下記のような構造体の定義です。

struct Person: Codable {
    let firstName: String
    let lastName: String
    let age: String
    let gender: String
}

ただ、一方でサーバの通信 API のレスポンスでは下記のような SnakeCase が用いられることがあります。

{
  "first_name": "Tetsuya",
  "last_name": "Hayashi",
  "age": "30",
  "gender": "male"
}

このような通信レスポンスを上記で定義した Codable を適用した Struct でパースしようとした場合、このままでは firstName と first_name で名称が異なるためパースができません。 このような場合は、Person を SnakeCase で書くか、以下のような CodingKey を別途定義する必要がありました。プロパティの数が少ない場合はまだ良いですが、毎回 CodingKey を定義するのも冗長な気がします。

struct Person: Codable {
    let firstName: String
    let lastName: String
    let age: String
    let gender: String

    private enum CodingKeys: String, CodingKey {
        case firstName = "first_name"
        case lastName = "last_name"
        case age
        case gender
    }
}

Swift 4.1 からはこの問題を解決するプロパティが JSONDecoder / JSONEncoder に追加されました。

keyDecodingStrategy / keyEncodingStrategy について

JSONDecoder に keyDecodingStrategy、JSONEncoder に keyEncodingStrategy プロパティが追加されています。これらのプロパティを設定することで、CamelCase ⇄ SnakeCase の変換を簡単に行うことができます。 例えば、先ほどの json を構造体の Person にパースする場合は下記のようになります。 CodingKeys が必要なくなり、随分すっきりしました。

let personJson = """
{
  "first_name": "Tetsuya",
  "last_name": "Hayashi",
  "age": "30",
  "gender": "male"
}
""".data(using: .utf8)!

let jsonDecoder = JSONDecoder()
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase // ここで snakeCase からの変換を指定

do {
    let person = try jsonDecoder.decode(Person.self, from: personJson)
    print(person)
} catch {
    print(error.localizedDescription)
}

逆に Encoding の際に、CamelCase を SnakeCase に変換することも可能です。

let person = Person(firstName: "Tetsuya", lastName: "Hayashi", age: "30", gender: "male")

let jsonEncoder = JSONEncoder()
jsonEncoder.keyEncodingStrategy = .convertToSnakeCase // ここで snakeCase への変換を指定
do {
    let json = try jsonEncoder.encode(person)
    print(json)
} catch {
    print(error.localizedDescription)
}

所感

Codable が登場した際はとても便利になったと驚きましたが、さらに改善されていきますね。 コードを書くのがより楽しくなりそうです。

参考資料