LoginSignup
37
23

More than 5 years have passed since last update.

JSONからCodable化されたstructを自動生成するツールを作った話

Last updated at Posted at 2018-09-30

はじめに

皆さん,Codableは使用していますか? 便利ですよね。

CodableによってJSONが簡単に扱えるようになった一方で,まだまだ途上という段階で,扱いづらさを覚えている方もいらっしゃるのではないでしょうか。

中でも,

Codable: Tips and Tricks

One of the major downsides of Codable is that as soon as you need custom decoding logic - even for a single key - you have to provide custom everything: manually define all the coding keys, and implementing an entire init(from decoder: Decoder) throws initializer by hand. This isn’t ideal.

とあるように,現在 (Swift 4.2) のCodableでは,(initは省略できるようになったものの) 対応するCodingKeysや,JSONの返すKeyに不足がある場合JSONDecoder().decode()が失敗するなど,面倒な場面があります。

自分で管理するAPIならまだしも,公開されているAPIで「何がOptionalで欠損しているのかが分からない!」といった場面に遭遇した際にはかなり苦戦させられます。
手動で「?」を付けたり,CodingKeyを追加したり。イヤですよね。

そこで,その作業を自動化するツールを作成しました。

作成したもの

JSONtoCodable という,生のJSONからCodable化されたstructを吐き出すツールを作成しました。

demo_macos.png

Demoをダウンロードし,JSONテキストを貼り付けて「Generate!」ボタンを押すと,よしなに解析,整形されたstructテキストを出力します。

例えば,

{
    "user": {
        "Name": "Yuto Mizutani"
    },
    "lib": {
        "lib-name": "JSONtoCodable",
        "year": 2018,
        "version": "1.0.2",
        "released": "2018-09-22"
    },
    "text": "Hello, world!!"
}

というJSONを入力した場合,

public struct Result: Codable {
    public let user: User
    public let lib: Lib
    public let text: String

    public struct User: Codable {
        public let name: String

        private enum CodingKeys: String, CodingKey {
            case name = "Name"
        }
    }

    public struct Lib: Codable {
        public let libName: String
        public let year: Int
        public let version: String
        public let released: String

        private enum CodingKeys: String, CodingKey {
            case libName = "lib-name"
            case year
            case version
            case released
        }
    }
}

というstructが生成されます。

CodingKeysは不要な場合省略され,JSONのKeyに対応した順序でstructに変換されていきます。
また,"foo": ["bar", "baz"]といった配列にも対応し,もし配列がオブジェクトであった場合には,欠損値に応じてOptional型に変換されます。

出力された値を貼り付けるだけでResponseまたはModelが完成するため,(特に初心者の方の) 開発を助けること間違いなしです!

Q. 何で作ったの?

「JSON Codable Swift」 などとGitHubで検索すれば確かに存在するように思えます。

一方で,5以上のネストされたオブジェクトに対応していなかったり, オブジェクトが辞書型になってしまっていたり,CodingKeyが機能せず変数名に使えない名前が定義される など,イマイチな代物ばかりでした。

誰もこの ロックなJSON をパスできなかったのです!

JSONtoCodableはオブジェクトがいくつネストしていても変換できます。

Q. 対応している型は?

現在は JSONtoCodable#translations の基本型のみです。将来的にDateやURLにも対応できるようにする予定です。

Q. 使用する上での注意は?

現在,JSONのvalueがStringとNumber型,または配列と値による複数型であった場合,エラーとして失敗せず,Any型や重複されたimmutableとして出力できてしまうようになっています。Swift4.2ではまだCodable内のAny型はコンパイルエラーとなってしまいます。
これは,Swift側で実行時にJSON側のエラーと見分けられるようにするため,現在は意図的にそうしています。エラーとして返してしまうと,どういう結果であったのか,すぐ直せるようなJSONのミスをError型で書き消してしまうのを防ぐためです。

Q. このJSON上手くいかないんだけど? / なんかコード汚ないんだけど?

上手くいかないケースがありましたら下記 issues にお願い致します。日本語でも対応致します。
可能であればJSONの失敗例がありますと,TDDで解決しやすくなり大変助かります!
https://github.com/YutoMizutani/JSONtoCodable/issues

コードが汚ないと感じた方,下記よりお待ちしております!
https://github.com/YutoMizutani/JSONtoCodable/pulls

おわりに

まずは,Demoを試していただきたいです。

そして,よければスターをお願い致します!

皆さんの開発ライフを少しでも手助けできれば幸いです。

追記 (2018/10/25)

CLIに対応しました!
curl等からパイプで繋いで生成することができるようになりました!

インストール

$ brew tap YutoMizutani/jc
$ brew install jc

使い方

$ curl https://httpbin.org/get | jc
$ curl https://httpbin.org/get | jc > Result.swift

screenshot

References

37
23
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
37
23