僕は普段はRubyやC#を書いているのですが、swiftでAPIを叩く機会がありまして、swift実践入門を読みました。
APIの章は14章です。
もうすこしDRYに書きたい
swift実践入門では、githubAPIを叩いて、 リポジトリの検索を行うといったものです。
以下、swift実践入門より引用して一部抜粋。
JSONDecodable.swift
protocol JSONDecodable {
init(json: Any) throws
}
User.swift
struct User: JSONDecodable {
let id: Int
let login: String
init(json: Any) throws {
guard let dictionary = json as? [String : Any] else {
throw JSONDecodeError.invalidFormat(json: json)
}
guard let id = dictionary["id"] as? Int else{
throw JSONDecodeError.missingValue(key: "id", actualValue: dictionary["id"])
}
guard let login = dictionary["login"] as? String else {
throw JSONDecodeError.missingValue(key: "login", actualValue: dictionary["login"])
}
self.id = id
self.login = login
}
}
JSONから各構造体にマッピングするときに、jsonをdictionaryに変換(+例外処理)、キーからバリューを取得(+例外処理)がやや冗長な気がします。これを各モデルに対して書くのは辛そうです。
少しDRYにしてみる
swift初心者ながら、DRYにリファクタしてみます。こうした方がいいとか、この書き方は危険だとかありましたらコメントで教えていただけると助かります。
JSONDecoderという別の構造体を作ってしまう
この人に加工と例外処理をお願いしてしまいます。
JSONDecoder.swift
struct JSONDecoder {
var dictionary: [String : Any]
init(json: Any) throws {
guard let dictionary = json as? [String : Any] else {
throw JSONDecodeError.invalidFormat(json: json)
}
self.dictionary = dictionary
}
func read<T>(key: String) throws -> T {
guard let value = dictionary[key] as? T else {
throw JSONDecodeError.missingValue(key: key, actualValue: dictionary[key])
}
return value
}
}
モデルを短く書いてしまう
User.swift
struct User: JSONDecodable {
let id: Int
let login: String
init(json: Any) throws {
let decoder = try JSONDecoder(json: json)
id = try decoder.read(key: "id")
login = try decoder.read(key: "login")
}
}
感想
かっちりした文法で慣れるまでに時間はかかりそうですが、慣れたら大変書きやすく保守しやすい言語だと思いました。
あと、API叩くにはこういうライブラリがおすすめとか、あったら教えてください。