🌊
iOS | Alamofire で GET して返ってきた JSON をデコードする
Qiita の API を使って記事を取得してみます。
まずは取得する記事のモデルを作成します。
モデルクラスで定義したプロパティ名と返却される JSON のキーを対応させる必要があるのですが、もし異なる場合はクラス内に CodingKeys という enum を作り、そこでキーを指定してあげます。プロパティ名はキャメルケースだけど JSON のキーはスネークケースの場合などはこの方法でキーを指定します。
【追記】
コメントでもっと簡単な方法を教えていただきました。
スネークケースからキャメルケースの変換だけであれば、JSONDecoder を使うことで CodingKeys の enum はまるっと不要になります(後述)。
struct Article: Codable {
let title: String
let commentsCount: Int
// private enum CodingKeys: String, CodingKey {
// case title
// // プロパティ名と JSON のキーが異なるので指定してあげる
// case commentsCount = "comments_count"
// }
}
次に Alamofire を使って記事を取得します。
responseDecodable(of:)
で返却されるモデルクラスを指定しておくと、let articles = response.value
とやるだけで JSON から変換されたモデルクラスのインスタンスを取得できます。今回は記事の配列を取得するので Array<Article>.self
を指定します。
【追記】
スネークケースからキャメルケースの変換を行う場合、responseDecodable(of:decoder:)
に JSONDecoder を指定することで簡単に変換ができます(まったく違う名前に変換したい場合は、引き続き enum CodingKeys で指定する必要があります)。
let url = "https://qiita.com/api/v2/items"
let params = [
"page": "1",
"per_page": "10",
]
// スネークケース -> キャメルケースを変換する場合、JSONDecoder を設定する
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
AF.request(url, parameters: params)
.validate(statusCode: 200..<300)
.responseDecodable(of: Array<Article>.self, decoder: decoder) { response in
switch response.result {
case .success:
if let articles = response.value {
print("articles: \(articles)")
} else {
print("articles is nil")
}
case .failure(let error):
print(error)
}
}
Discussion
この部分ですが、
JSONDecoder.KeyDecodingStrategy | Apple Developer Documentation
これを使って
JSONDecoder.KeyDecodingStrategy.convertFromSnakeCase
を指定すると今回の場合は enum ごと無くせると思います。responseDecodable
の実装は この辺り を見るととなっていますので、ここに自前の
JSONDecoder
を渡せば行けそうです。実際に試したわけではないのでそのまま動くかは自信ないですが、
このようなイメージになります。
ご丁寧にコメントありがとうございます!
こちら試したところ、ちゃんと動いているのが確認できたので記事を更新しました🙇♂️
モデルクラスが持つプロパティが多くなると CodingKeys が肥大化してしまうなーと思っていたのですが、これでスッキリしそうです!とても助かります!