Swift GoogleBook APIで書籍検索
作業フロー
1-エンドポイントの調査
2-API Keyの取得
3-jsonデータの分析
4-コード作成
5-iOSにてView作成
1-エンドポイント、(接続するアドレス)はここに記載されている
https://developers.google.com/books/docs/v1/using
具体的にはここ
https://www.googleapis.com/books/v1/volumes?q=flowers+inauthor:keyes&key=yourAPIKey
&keyのkey部分へ自分のキーを配置する
2-keyを取得してエンドポイントへアクセスする。するとこの様なjsonデータが返却される。
これを解析する。 今回はここに時間をかける。
{ "kind": "books#volumes", "totalItems": 100, "items": [ { "kind": "books#volume", "id": "_oG_iTxP1pIC", "etag": "fPjIOwmEaME", "selfLink": "https://www.googleapis.com/books/v1/volumes/_oG_iTxP1pIC", "volumeInfo": { **//ここの配下のtitleとdescriptionを取得したい** "title": "Flowers for Algernon", "authors": [ "Daniel Keyes" ], "publisher": "Houghton Mifflin Harcourt", "publishedDate": "2007-12-01", "description": "The beloved, classic story of a mentally disabled man whose experimental quest for intelligence mirrors that of Algernon, an extraordinary lab mouse.", "industryIdentifiers": [ { "type": "ISBN_10", "identifier": "0547539630" }, {
今回はtitleとdescriptionを取得することを目的とする。
構造体を宣言
欲しいものだけ最低限取得する。
型はエンコード、デコードできる、Codable型
まずitemsの取得、items配下は配列になっているのでItem型の配列とする。 nilになる可能性のないものはオプショナル型でなくても良い。
jsonデータ
"items": [ //ここで、配列ということがわかります。 { "kind": "books#volume", "id": "_oG_iTxP1pIC",
Swiftでの記載
struct SearchResut: Codable { let kind:String let items:[Item] // Item型の配列 }
更にたどっていくと、volumeInfoの下に目的のtitleとdescriptionがある。
ここはjsonオブジェクトなので、配列ではない。
VolumeInfoはVolumeInfo型にする。このようにして、型だけを継承していくイメージ。
あくまでもイメージ。構造体は継承できない。
struct Item: Codable{ let volumeInfo:VolumeInfo }
VolumeInfoの下に目的のtitleとdescriptionがある。
それは、String型
これ以上の階層は追っかけない。
struct VolumeInfo: Codable{ let title:String let description:String }
これで、受け取る用意はできた。 あとはjsonの取得。
//リクエストURL作成 guard let req_url = URL(string: "https://www.googleapis.com/books/v1/volumes?q=\(keyword_encode)") else{ return books
nilになる可能性があるので、guard文にしておく。
httpの取得は、通信エラーなどでnilが返却されることがあるので注意が必要。
本当は非同期処理がいい。 NSURLSessionクラスを利用すれば、非同期ででききる 他にもAlamofireという非同期処理のライブラリがある。これがいいらしい。
エラーの可能性があるので, Swiftのエラー処理である、do~catchで囲む nilでも落ちないので便利。
static func searchBooks(keyword:String)->[BookInfo]{ //返却したい型 var books:[BookInfo] = [] do{ //urlをデータ型へ変換 let data = try Data(contentsOf: req_url) //これで非同期処理にならない。 //jsonをデコード let searchResult = try JSONDecoder().decode(SearchResut.self, from: data) //デコードしたjsonを詰め込むsearchResultがトップなので、itemsはそのプロパティとして持っている for item in searchResult.items{ //item配下のvolumeInfoを詰め込む let volumeInfo = item.volumeInfo //volumeInfo配下のtitleを詰め込む let title = volumeInfo.title //volumeInfo配下のdescriptionを詰め込む。同じ階層にある let description = volumeInfo.description //最後に返却したい型を別の箇所で宣言している。bookInfo型 下記に記載 let bookInfo = BookInfo(title: title, description: description) //配列に詰め込んでいく books.append(bookInfo) } }catch{ print("エラーが出ました") } //BookInfo型の配列で返却 return books }
bookInfo型
struct BookInfo{ var title:String var description:String? }
これで戻り値でほしい書籍データを取得できた。
必要ないと思うが,TableViewへの表示も記載しておく。
//add var bookList:[BookInfo]? override func viewDidLoad() { super.viewDidLoad() //先程の関数 bookList = searchBooks(keyword: keyword!) //tableViewのデリゲートメソッドを2つ記載しないとエラーになる。 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return bookList!.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "bookCell", for: indexPath) cell.textLabel?.text = bookList![indexPath.row].title cell.textLabel?.font = UIFont.systemFont(ofSize: 15) return cell }