66
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftAdvent Calendar 2014

Day 19

Swift で WebAPI を叩いてみる

Posted at

アプリを作っていると WebAPI を叩く機会が多いと思いますが、今回は Swift で書いてみました。

これはなに

  • 便利ライブラリの紹介
  • あえて NSURLSession を使って叩く
  • テスト書く

便利ライブラリ

後で紹介する NSURLSession を使ってもよいのですがいろいろと骨が折れるのでライブラリを使いましょう。
GET, POST, PUT, DELETE に対応していれば大体の API が叩けると思います。

Alamofire

みんな大好き Alamofire 。いろんなところで紹介されているので「またか」という人もいるのではないでしょうか。
高機能で美しくレスポンスを受け取れるのがいいですね。
個人的には

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .response { (request, response, data, error) in
                     println(request)
                     println(response)
                     println(error)
                   }

と request, response をメソッドチェイン的に書けるのが美しいですね。

Net

Alamofire 一強みたいな雰囲気がありますが、 Net というライブラリもあります。
ぼくはこっちを先に知ったのでよく使っています。素直に NSURLSession をラップしている、という感じで Objective-C 書いてたエンジニアは親しみやすいと思います(今となっては Alamofire の方がいいなあ…と思っている)。また、実装自体も追いやすいので拡張させたりできます。

let url = "http://www.puqiz.com/get_path"
net.GET(absoluteUrl: url, params: params, successHandler: { responseData in
        let result = responseData.json(error: nil)
        NSLog("result \(result)")
    }, failureHandler: { error in
        NSLog("Error")
    })

コードはそれぞれの README から拝借しました。

ライブラリを導入してみる

  • git-submodule
  • cocoapods

git-submodule で入れる

後述の cocoapods が正式に対応していない以上、git-submodule で入れるのが一般的なのかなあと思います。みなさんはどうですか。
よく README に書いてあるのが

hoge.swift を直接 Project に入れてね

というようなことですね。 git clone して入れてもいいですが Swift はすぐ仕様が変わるし、どのライブラリもアクティブにコミットされているのが多いので git submodule で導入するのがいいと思います。
コマンドの使い方などは http://qiita.com/sotarok/items/0d525e568a6088f6f6bb このへんを読めばいいです。

悪い点

  • 管理すべきものが git-submodule と cocoapods で分散する

ただでさえ pod update するのもめんどくさいのに git submodule update を打たないといけなくなり大変めんどくさくなります。

cocoapods で入れる

現在、cocoapods は Swift に対応していませんが、 swift branch に checkout すればなんとか使うことができます。
詳しくは Web で: http://swiftwala.com/cocoapods-is-ready-for-swift/

プロジェクトルートに Gemfile を作成

Gemfile
source 'https://rubygems.org'

gem 'cocoapods', :git => 'https://github.com/CocoaPods/CocoaPods.git', :branch => 'swift'
gem 'cocoapods-core', :git => 'https://github.com/CocoaPods/Core.git'
gem 'xcodeproj',  :git => 'https://github.com/CocoaPods/Xcodeproj.git'
gem 'claide', :git => 'https://github.com/CocoaPods/CLAide.git'

bundle install する

$ bundle install

Podfile を編集

Podfile
source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '8.0'
pod 'SwiftyJSON', :git => "https://github.com/orta/SwiftyJSON", :branch => "podspec"
pod 'Alamofire', :git => "https://github.com/mrackwitz/Alamofire.git", :branch => "podspec"

この例だと SwiftyJSON と Alamofire を導入しています。

pod install する

$ bundle exec pod install

毎回 bundle exec が必要なようです。

NSURLSession で叩いてみる

ライブラリを紹介したあとで蛇足感ありますが、Swift で書いてみます。
今回は tiqav の API を叩いてみました。

APIRequest.swift
import Foundation

class APIRequest {
    init() {
        // 初期化
    }
    
    class func getRandom() {
        let url = NSURL(string: "http://api.tiqav.com/search/random.json")
        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: config)
        
        let request = NSURLRequest(URL: url!)
        let task = session.dataTaskWithRequest(request, completionHandler: {
            (data, response, error) in
            switch (data, response, error) {
            case (_, _, .Some(error)):
                // エラー処理
                println(error.localizedDescription)
            case (.Some(data), .Some(response), _):
                if (response as NSHTTPURLResponse).statusCode == 200 {
                    // なんか処理
                    var error: NSError?
                    let jsonArray = NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments, error: &error) as NSArray
                    println(jsonArray)
                } else {
                    // 処理
                }
            default:
                break
            }
        })
        
        task.resume()
    }
}

Swift の良いところは tuple にあると思います。
request の結果が (data, response, error) というタプルで返ってくるのでエラー処理などを if 文書かずに switch で分けて書くことができます。
Swift の Optional には .Some.None があるのでそれで nil かどうかを調べることができます。
それについては この記事 が詳しいです。
tuple で処理するところ以外は Objective-C と同じなので説明する必要はないでしょう。
というかこの switch 文の場合分けの記事をどこかで見た気がしたんだが忘れてしまったのでご存知の方教えていただけると助かります。

テスト書く

API 叩くあたりのクラスはちゃんとテストを書きたいですね。
というと、

  • レスポンスのモックを用意する
  • HTTPRequest をフックしてモックを返すようにする

ということが必要になりそうですね。

OHHTTPStubs

そのようなライブラリはたくさんありますが、一応これを紹介しておきます。
ただ、Objective-C で書かれており、cocoapods で導入したところうまく動きませんでした。
原因としては Objective-C のマクロを Swift がうまく処理できないのかなあというエラーがでていましたがイマイチ不明です。

aerogear-ios-httpstub

こちらは OHHTTPStubs の Swift 移植のものです。これはうまく動きました。

StubsManager.stubRequestsPassingTest({ (request: NSURLRequest!) -> Bool in
    return true
}, withStubResponse:( { (request: NSURLRequest!) -> StubResponse in
     return StubResponse(filename: "mystubbedjson.json", location:.Bundle(NSBundle(forClass: AGURLSessionStubsTests.self)), statusCode: 200, headers: ["Content-Type" : "text/json"])
}))

というようなコードを HTTP リクエストを送る前に呼んでおくとフックして、この例だと mystubbedjson.json を返してくれるというわけです。
これでいつでも同じレスポンスを得ることができ、API のテストが書けるというわけです。

まとめ

  • メソッドチェインで書くとかっこいい
  • タプル使うと見やすく書ける
  • cocoapods の Swift 対応を求む
  • Swift 移植のライブラリも登場しはじめており非常に期待がもてる

長くなってしまいましたが終わりです。 Swift は見やすいコードが書けるのでとてもいいですね。

66
69
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
66
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?