APIKitで定義したRequestからNSURLRequestを生成して使う

Monday, March 21, 2016

たまにはPCから離れて生活するのも有りだなと思って、金曜の夜から今日の昼までほとんどPCを開かずに過ごしました。
その間にFeedlyで記事がたまりに溜まっていましたが、毎日数時間毎にFeedlyに張り付いて確認するよりは気持ち的には楽でした。笑

今日は、 APIKit で定義したRequestのURLをビルドして用いる方法のメモを残していきます。

特定のAPIだけ、APIKitでの通信ではなくて、WebView等で通信したい

基本的には APIKit で定義したRequestを、APIKitのSessionに流して通信を行うのですが、定義したRequestの一部をWebViewで行いたい場合があります。
例えば、 OAuth 認証みたいに、APIを叩いて、その認証をユーザーに行わせる画面のHTMLを返却するような場合に、
WebViewでURLと必要なパラメータを送信すれば表示できますが、 APIKit のSessionにRequestを投げてHTMLを取得してから表示…としようとするとうまくいかない場合が有ります。
そうなった時に、APIKitから外れて NSURLRequest を定義して…っていうのも一つの手ですが、

  • 他のAPIと共通のBaseURL等の定義箇所が増えてしまうので、何か変更があったときに面倒
  • 他のAPIと同じように定義しておきたい

といった問題が出てきます。
自分もこれで躓いてどうするんだろうと思ってAPIKitのソースを眺めていたら、解決策が見つけられました。

APIKitbuildURLRequest()を使う

RequestType を継承していれば、buildURLRequest()を用いてNSURLRequestを生成することができます。
定義はこのようになっています。

public func buildURLRequest() -> Result.Result<NSURLRequest, APIKit.APIError>

APIKit では、Resultを利用しているので、この関数で返される値は、NSURLRequestAPIErrorが入ったenumになっています。
なので、必要があれば返ってきたResult型のenumを検証して、NSURLRequestが使えるか調べる必要があります。

switch request.buildURLRequest() {
case .Success(let request):
    webView.loadRequest(request)
case .Failure(let error):
    print(error)
}

もし、確実にNSURLRequestが作られる!というのが保証できるのであれば、以下のように書くこともできます。

webView.loadRequest(requestbuildURLRequest().value!)



使用例

あるAPISomeAPIがあって、その一つにAuthorizeRequestというRequestがあったときに、
APIKitのSessionで通信するのではなくて、SFSafariViewControllerにURLを渡して通信を行う場合の例です。

final class SomeAPI {

}

protocol SomeRequestType: RequestType {

}

extension SomeRequestType {
    var baseURL: NSURL {
        return NSURL(string: "https://some.com/api/v9")!
    }
}

extension SomeAPI {
    struct AuthorizeRequest: SomeRequestType {
        typealias Response = AnyObject

        var method: HTTPMethod {
            return .GET
        }

        var path: String {
            return "/oauth/authorize"
        }

        var parameters: [String: AnyObject] {
            return [
            "client_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            ]
        }

        func responseFromObject(object: AnyObject, URLResponse: NSHTTPURLResponse) -> Response? {
            return nil  // Sessionでの通信がないので、何かする必要はなし
        }
    }
}

こんな感じに定義して、

import SafariServices

func openOAuth() {
    let safariVC = SFSafariViewController(URL: SomeAPI.AuthorizeRequest().buildURLRequest().value!.URL!)
    presentViewController(safariVC, animated: true, completion: nil)
}

とすることで、無事APIKitでの定義を活かしつつ、NSURLRequest(この例では更にNSURLを取得しています)を作って利用することができます。

techSwiftTipsAPIKit

文字列を指定した長さずつ分割する

clocコマンドでプロジェクト内のファイル数や行数を言語毎に見る