2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

キャメルケースとパスカルケースが入り混じったJSONをCodableで扱う

Last updated at Posted at 2019-02-20

最近のRestfulなAPIなら無いと思いますが、業務で別の会社がサーバを担当するケースでは稀にそういったクソみたいなAPIにブチ当たる場合があります~~(というか現在進行系でぶち当たってて頭を抱えてる状態😂)~~。

例えばこんな感じ

{
    "ResponseHeader": {
        "status": "0",
        "message": "",
        "validationErrorMessages": []
    },
    "itemList": [
        {
            "name": "hoge"
        }
    ]
}

いやもうResponseHeaderってなんやねんってツッコミは置いといて、
こういうJSONをCodableで扱おうとするとCodingKeyを用意しないといけなくて面倒です。

Response.swift
struct Response: Codable {
    let responseHeader: ResponseHeader
    let itemList: [Item]

    enum CodingKeys: String, CodingKey {
        case responseHeader = "ResponseHeader"
        case itemList
    }
}

しかし、JSONDecoderkeyDecodingStrategyを使えばなんとかできるのではなかろうかと思って検証してみました。

JSONEncoder.KeyEncodingStrategy.custom(@escaping ([CodingKey]) -> CodingKey)についてはAppleのドキュメントこの記事が参考になります。
↑を元にまずはResponseKeyを作ります。

ResponseKey.swift
struct ResponseKey: CodingKey, ExpressibleByStringLiteral {
    typealias StringLiteralType = String

    var stringValue: String
    var intValue: Int?

    init(stringLiteral value: String) {
        self.stringValue = value
        self.intValue = nil
    }

    init?(stringValue: String) {
        self.stringValue = stringValue
        self.intValue = nil
    }

    init?(intValue: Int) {
        self.stringValue = String(intValue)
        self.intValue = intValue
    }
}

そしてJSONDecoderをこんな感じで設定してあげます。

decoder.swift
var decoder: JSONDecoder {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .custom { keys in
        // 先頭文字を小文字にする
        let key = keys.last!.stringValue.lowercasingFirst
        return ResponseKey(stringLiteral: key)
    }
    return decoder
}

こうすることで、このdecoderを使ってデコードするJSONは全てのキーを先頭小文字に変換して扱ってくれるようになります。
つまり、キャメルケースであろうとパスカルケースであろうと問答無用でキャメルケースとして扱うわけです。

これで、上のResponseCodeingKeyを定義することなく、シンプルに

Response.swift
struct Response: Codable {
    let responseHeader: ResponseHeader
    let itemList: [Item]
}

と書くことができるようになります。

ちなみにJSONDecoder.KeyDecodingStrategy.customで用意するクロージャがなぜ[CodingKey] -> CodingKeyなのかはドキュメントを読んでみてもいまいちピンと来ませんでした。

なぜだ...🤔

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?