【iOS】Alamofire + Himotokiでいい感じのAPIクライアントを作る
どうも、社内開発でiOSを担当してる朝倉です。
現在、夏期休業中ですが、そういえばブログ更新しないといけないなと思い出したので書きます。
Alamofire + HimotokiでAPIクライアントを作るということで、n番煎じだしもっといい方法がネット上にはゴロゴロある気がするのですが、 現状、(僕が)いい感じだと思っている実装を書いてみたいと思います。
導入
CocoaPodsでAlamofireとHimotokiを導入します。
「そんなの知ってるよ」とかCarthage派の人やSPM派の人は読み飛ばしてください。
ターミナルでプロジェクトディレクトリへ移動し、
pod init
Podfileが作成されるので以下の2行を追加します。
pod 'Alamofire', '~> 4.4' pod 'Himotoki', '~> 3.0'
このようになればOKです。
target 'プロジェクト名' do use_frameworks! pod 'Alamofire', '~> 4.4' pod 'Himotoki', '~> 3.0' end
Podfileを保存し、
pod install
これで、AlamofireとHimotokiがプロジェクトに追加されたので、プロジェクト名.xcworkspaceファイルを開きます。
APIクライアントを作る
今回は、GitHubのAPIを使用します。 まずは共通の通信部分を作成します。
import Alamofire import Himotoki enum Result<T> { case Success(T) case Error(Error) } protocol APIRequest { var baseeUrl: String { get } var headerTemplate: [String : String] { get } associatedtype Response var path: String { get } var method: HTTPMethod { get } var parameters: [String : Any]? { get set } var headers: [String : String]? { get set } func response(from object: Any) throws -> Self.Response } extension APIRequest { var baseeUrl: String { return "https://api.github.com" } var headerTemplate: [String : String] { return ["X-Requested-With" : "XMLHttpRequest"] } var parameters: Any? { return nil } var headers: [String : String]? { return nil } func request(finished: @escaping (Result<Self.Response>)->Void) { let encoding = JSONEncoding.default var header = headerTemplate as Dictionary<String, String> headerTemplate.forEach() { header[$0.0] = $0.1 } let encodedURLString = (baseeUrl + path).addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed) Alamofire.request(encodedURLString!, method: method, parameters: parameters, encoding: encoding, headers: header).responseJSON { response in switch response.result { case .success(let value): print(value) do { let res = try self.response(from: value) finished(Result.Success(res)) } catch { finished(Result.Error(error)) } case .failure(let error): finished(Result<Self.Response>.Error(error)) } } } }
続いて、Decodableプロトコルを適応したモデルとAPIRequestプロトコルを適応したリクエストオブジェクトを作成していきます。
ユーザのリポジトリを取得する
import Himotoki import Alamofire struct Repository: Decodable { let fullName: String let ownerAvatarUrl: String let language: String? let url: String let htmlUrl: String static func decode(_ e: Extractor) throws -> Repository { return try Repository( fullName: e <| "full_name", ownerAvatarUrl: e <| ["owner", "avatar_url"], language: e <|? "language", url: e <| "url", htmlUrl: e <| "html_url" ) } } struct UserRepository: APIRequest { var headers: [String : String]? = nil var parameters: [String : Any]? = nil var userName: String var path: String { return "/users/\(self.userName)/repos" } var method: HTTPMethod { return .get } typealias Response = [Repository] init(userName: String) { self.userName = userName } func response(from object: Any) throws -> Response { return try decodeArray(object) } }
今後、エンドポイントが増えた場合にはDecodableプロトコルを適応したレスポンスモデルとAPIRequestプロトコルを適応したリクエストオブジェクトを増やしていけばいいだけなのでお手軽です。
使い方
UserRepository(userName: "asashin227").request() { result in switch result { case .Success(let responce): print(responce) case .Error(let error): print(error.localizedDescription) } }
ソース
とりあえずGitHubにあげたので参考にご利用ください。