堅牢で使いやすいAPIクライアントをSwiftで実装したいをライブラリにまとめてAPIKitとしてリリースしました。 なお、”Swiftらしい”というのは主観です。

https://github.com/ishkawa/APIKit

利用側のコード

  • リクエストに渡すパラメーターは型によって明らかになっている。
  • レスポンスはモデルオブジェクトとして受け取れる。
  • 成功時にレスポンスを非オプショナルな値で受け取れる。
  • 失敗時にエラーを非オプショナルな値で受け取れる。
// リクエストに渡すパラメーターを型で制限
let request = GitHub.Endpoint.SearchRepositories(query: "APIKit", sort: .Stars)

GitHub.sendRequest(request) { response in
    // optional bindingを使わずにレスポンスやエラーを取得
    switch response {
    case .Success(let box):
        // レスポンスの型はリクエストの型から推論される (ここでは[Repository])
        self.repositories = box.unbox
        self.tableView?.reloadData()

    case .Failure(let box):
        // 失敗時にはNSErrorがboxに入る
        println(box.unbox)
    }
}

APIの定義

  • 1つのエンドポイントに対する記述が1箇所で済む。
  • パラメーターにenumが使える。
  • 必須でないパラメーターはinitにデフォルト引数を与えておけば省略できる。
class GitHub: API {
    // base URLを指定
    override class func baseURL() -> NSURL {
        return NSURL(string: "https://api.github.com")!
    }

    // リクエストボディの指定
    override class func requestBodyBuilder() -> RequestBodyBuilder {
        return .JSON(writingOptions: nil)
    }

    // レスポンスボディの指定
    override class func responseBodyParser() -> ResponseBodyParser {
        return .JSON(readingOptions: nil)
    }

    // 各エンドポイントの設定
    class Endpoint {
        // https://developer.github.com/v3/search/#search-repositories
        class SearchRepositories: Request {
            enum Sort: String {
                case Stars = "stars"
                case Forks = "forks"
                case Updated = "updated"
            }

            enum Order: String {
                case Ascending = "asc"
                case Descending = "desc"
            }

            typealias Response = [Repository]

            let query: String
            let sort: Sort
            let order: Order

            var URLRequest: NSURLRequest? {
                return GitHub.URLRequest(.GET, "/search/repositories", ["q": query, "sort": sort.rawValue, "order": order.rawValue])
            }

            init(query: String, sort: Sort = .Stars, order: Order = .Ascending) {
                self.query = query
                self.sort = sort
                self.order = order
            }

            func responseFromObject(object: AnyObject) -> Response? {
                var repositories = [Repository]()

                if let dictionaries = object["items"] as? [NSDictionary] {
                    for dictionary in dictionaries {
                        if let repository = Repository(dictionary: dictionary) {
                            repositories.append(repository)
                        }
                    }
                }

                return repositories
            }
        }
    }
}

まだつくったばかりなので足りない機能もあると思いますが、是非試してみてください。