はじめに
初投稿なので、お手柔らかに!
Swiftは、テケテケ初心者ですが、
業務でAPIをよく使うので、APIクライアントを作ってみます。
ゴール
Alamofire + ObjectMapper を利用して、APIクライアントを作っちゃ。(富山弁)
利用するAPIについて
今回は、iTunesのSearch APIを例に実装してみます。
http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html#searching
やること
・APIをコールし、レスポンスデータをパースする。
やらないこと
・検索画面
・検索結果画面(レスポンスデータを保存する、UIに反映させる)
・Carthageのインストールや設定
実装手順
- AlamofireとObjectMapperをCarthageを利用して取り込む。
- DTOクラス(APIのレスポンス)を作成する。
- APIクライアントを作成する。
- APIクライアントを実装する。
いざ、チャレンジ
1. AlamofireとObjectMapperをCarthage(カルタゴ)を利用して取り込む。
プロジェクト配下に、Cartfileファイルを作成し、フレームワークを取り込む。
github "Alamofire/Alamofire" ~> 3.0
github "Hearst-DD/ObjectMapper" ~> 1.0
フレームワークの取り込み方は、割愛します。
詳しくは、下記の記事が参考になります。
http://qiita.com/yuta-t/items/97fe9bc2bf2e97da7ec1
2. DTOクラス(レスポンス)を作成する。
Search APIのレスポンス(JSON)は、下記のとおりです。
results部分がJSON Array(配列)になっています。
{
"resultCount": 1,
"results": [
{
"artistId": 671759255,
"artistName": "サザンオールスターズ",
"artistViewUrl": "https://itunes.apple.com/jp/artist/sazanorusutazu/id671759255?uo=4",
"artworkUrl100": "http://is5.mzstatic.com/image/thumb/Music1/v4/62/cf/41/62cf41fd-beae-b407-6b6b-b6524fb0a824/source/100x100bb.jpg",
"artworkUrl30": "http://is5.mzstatic.com/image/thumb/Music1/v4/62/cf/41/62cf41fd-beae-b407-6b6b-b6524fb0a824/source/30x30bb.jpg",
"artworkUrl60": "http://is5.mzstatic.com/image/thumb/Music1/v4/62/cf/41/62cf41fd-beae-b407-6b6b-b6524fb0a824/source/60x60bb.jpg",
"collectionCensoredName": "東京VICTORY - Single",
"collectionExplicitness": "notExplicit",
"collectionId": 949250439,
"collectionName": "東京VICTORY - Single",
"collectionPrice": 750.0,
"collectionViewUrl": "https://itunes.apple.com/jp/album/dong-jingvictory/id949250439?i=949250542&uo=4",
"country": "JPN",
"currency": "JPY",
"discCount": 1,
"discNumber": 1,
"isStreamable": false,
"kind": "song",
"previewUrl": "http://a455.phobos.apple.com/us/r30/Music1/v4/79/d9/88/79d9882f-8481-c68d-c131-be3f8c01c602/mzaf_6920758322735728543.plus.aac.p.m4a",
"primaryGenreName": "J-Pop",
"releaseDate": "2014-09-10T07:00:00Z",
"trackCensoredName": "東京VICTORY",
"trackCount": 3,
"trackExplicitness": "notExplicit",
"trackId": 949250542,
"trackName": "東京VICTORY",
"trackNumber": 1,
"trackPrice": 250.0,
"trackTimeMillis": 309467,
"trackViewUrl": "https://itunes.apple.com/jp/album/dong-jingvictory/id949250439?i=949250542&uo=4",
"wrapperType": "track"
}
]
}
データ項目の種類が多いため、
今回は、TrackIDとTrackName、artistNameの3つのみパースします。
データ項目 | 説明 |
---|---|
TrackID | トラックID(iTunesが管理しているID) |
TrackName | トラック名(曲名) |
artistName | アーティスト名 |
パース処理は、「ObjectMapper」というライブラリを使います。
Swiftの場合、「SwiftyJSON」を利用しているサンプルが多いですが
個人的には、「ObjectMapper」がお気に入りです。
まずは、ソースコードから見てください。
基本的には、JSONのキーと管理する構造体のプロパティを
マッピングするだけです。
import ObjectMapper
struct Results: Mappable {
var resultCount = 0
var results: [Track]?
init?(_ map: Map){}
mutating func mapping(map: Map) {
resultCount <- map["resultCount"]
results <- map["results"]
}
}
struct Track: Mappable {
var trackName = ""
var trackId = ""
var artistName = ""
init?(_ map: Map){}
mutating func mapping(map: Map) {
trackId <- map["trackId"]
trackName <- map["trackName"]
artistName <- map["artistName"]
}
}
3. APIクライントを作成する。
今回は、APIClient.swiftとします。
通信部分は、定番の「Alamofire」を利用します。
iOS8以上をサポートしているようです。
ちなみに、iOS7でもAlamofire.swiftを足せばいけるらしい
(iOS7はやく消えてくれ!)
3.1. 外枠を作ります。
APIのレスポンスを複数パターンのデータ型に対応するため
ジェネリックスで定義します。。
import Alamofire
import ObjectMapper
enum Result<T> {
case Success(T)
case Error(NSError)
}
class APIClient<T> {
}
3.2. リクエストURLの作成
今回利用するSearch APIのリクエストURLは、下記のとおりです。
「https://itunes.apple.com/search?parameterkeyvalue」
項目 | 説明 |
---|---|
BaseURL | https://itunes.apple.com |
APIパス | search |
HTTPメソッド | GET |
リクエストパラメタ | オプションがいろいろある |
この部分は、enumのAssociated Valueを使ってみます。
enum Router: URLRequestConvertible {
static let baseURLString = "https://itunes.apple.com"
case API_SEARCH([String: AnyObject])
var URLRequest: NSMutableURLRequest {
let (method, path, parameters) : (String, String, [String: AnyObject]) = {
switch self {
case .API_SEARCH(let params):
return ("GET", "/search", params)
}
}()
let URL = NSURL(string: Router.baseURLString)
let URLRequest = NSMutableURLRequest(URL: URL!.URLByAppendingPathComponent(path))
URLRequest.HTTPMethod = method
let encoding = Alamofire.ParameterEncoding.URL
return encoding.encode(URLRequest, parameters: parameters).0
}
}
APIの種類が増えると、Caseを増やしていくイメージです。
3.3 APIクライントにアクセスメソッドを追加する。
呼び出し元から呼びやすいようにラップしているだけです。
func iTunesSearch(params : [String: AnyObject], completionHandler: (Result<T>) -> () = {_ in}) {
Alamofire.request(Router.API_SEARCH(params))
.validate()
.responseJSON { response in
switch response.result {
case .Success:
if let resp = Mapper<Results>().map(response.result.value) {
completionHandler(Result<T>.Success((resp as? T)!))
}
case .Failure(let error):
completionHandler(Result<T>.Error(error))
}
}
}
4. APIクライントを実装する。
APIクライアントをコールしてみます。
リクエストパラメタもいろいろあるため、
必須パラメタだけ指定することとします。
パラメタ | 説明 |
---|---|
term | 検索キーワード |
country | 国 (例) jp |
APIをコールするときは、APIレスポンスのデータ型に合わせて指定します。
今回は、DTOクラスで作ったResults型を指定しています。
(ResultsとResultと分かりづらいですが、データ型はJSONのキーに合わせるのが、定石のようです。)
@IBAction func searchMusic(term: String) {
APIClient<Results>().iTunesSearch(["term" : term, "country" : "jp"]) { (response) -> () in
switch response {
case .Success(let itunesSearch):
for result in itunesSearch.results! {
//とりあえず、トラック名をコンソールに出力
print(result.trackName)
}
break
case .Error(let error):
print(error)
break
}
}
}
検索キーワードに「サザン」と入れてみました。
無事、トラック名の一覧が取得できました。
やったー
東京VICTORY
TSUNAMI
イヤな事だらけの世の中で
LOVE AFFAIR~秘密のデート
真夏の果実
蛍
アロエ
はっぴいえんど
HOTEL PACIFIC
いとしのエリー
涙のキッス
東京VICTORY
ピースとハイライト
エスとハイライト
エ\343ロティカ・セブン EROTICA SEVEN
栄光の男
蛍
ピースとハイライ蛍
ピースとハイライ\343\203ト
Missing Persons
ミス・ブランニュー・デイ(MISS BRAND-NEW DAY)
真夏の果実
平和の鐘が鳴る
バラ色の人生
勝手にシンドバ生
勝手にシンドバ\343\203ッド
青春番外地
天井棧敷の怪人
ワイングラスに消えたワイングラスに消えた\346恋
彼氏になりたくワイングラスに消えた\346恋
彼氏になりたく\343\201て
みんなのうた
栞のテーマ
天国オン・ザ・ビーチ
道
Bye Bye My Love(U are the one)
愛の言霊 ~Spiritual Message~
マンピーのG★SPOT
太陽は罪な奴
匂艶 THE NIGHT CLUB
あなただけを ~Summer Heartbreak~
夏をあきらめて
C調言葉に御用心
逢いたくなった時に 君はここにいない
海
チャコの海岸物語
そんなヒロシに騙されて
Ya Ya(あに騙されて
Ya Ya(あ\343\201の時代を忘れない)
に騙されて
Ya Ya(あ\343\201の時代を忘れない)
\343\202クリスマス・ラブ(涙のあに騙されて
Ya Ya(あ\343\201の時代を忘れない)
\343\202クリスマス・ラブ(涙のあ\343とには白い雪が降る)
いなせなロコモーション
YOU
鎌倉物語
TSUNAMI
さよならベイビー
まとめ
Swiftは、structやenumなどが拡張され、
class、struct、enumのどれを利用してもやりたいことが実現できそうですね。
ただし、どの場面でどの手法をとるか、エンジニアの技量が試されそうです。
メモリ管理上の観点(値型、参照型)など、メリット・デメリットを整理し、
こうあるべきだという、コーディング規約ができたら、いいなー
有志の方へ
もっとこうしたら良いよなど、
アドバイスをお待ちしております。