Skip to content

Instantly share code, notes, and snippets.

@syou007
Created April 24, 2017 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syou007/bdfb06fe117c36b909eb84ffa1a8a723 to your computer and use it in GitHub Desktop.
Save syou007/bdfb06fe117c36b909eb84ffa1a8a723 to your computer and use it in GitHub Desktop.
SwiftでAPIリクエストを発行する。 ref: http://qiita.com/syou007/items/566a62ee5eaa96f5a2d3
import UIKit
import Alamofire
import RxSwift
import ObjectMapper
import AlamofireObjectMapper
// Routerを実装してAPIを作成ます。
public protocol Router {
// URLを返却
func url() -> String
// メソッドを返却
func method() -> Alamofire.HTTPMethod
// 実際のデータ取得処理
func request<T: Mappable>() -> Observable<[T]>
func request<T: Mappable>() -> Observable<T>
func request<T: Mappable>(parameters: Parameters?) -> Observable<[T]>
func request<T: Mappable>(parameters: Parameters?) -> Observable<T>
// エラー時の処理
func errorHandle(error: Error, statusCode: Int?)
}
// Routerの共通処理をあらかじめ定義しておく。
extension Router {
// Defaultはget処理
func method() -> Alamofire.HTTPMethod { return .get }
// 実際のリクエスト発行
func request<T: Mappable>() -> Observable<[T]> {
return self.request(parameters: nil)
}
func request<T: Mappable>(parameters: Parameters? = nil) -> Observable<[T]> {
return Observable.create { (observable: AnyObserver<[T]>) in
// リクエストを投げる。
API.createRequest(router: self, parameters: parameters).responseArray { (response: DataResponse<[T]>) in
switch response.result {
case .success(let value):
observable.on(.next(value))
observable.onCompleted()
case .failure(let error):
self.errorHandle(error: error, statusCode: response.response?.statusCode)
}
}
return Disposables.create()
}
}
func request<T: Mappable>() -> Observable<T> {
return self.request(parameters: nil)
}
func request<T: Mappable>(parameters: Parameters? = nil) -> Observable<T> {
return Observable.create { (observable: AnyObserver<T>) in
// リクエストを投げる。
API.createRequest(router: self, parameters: parameters).responseObject { (response: DataResponse<T>) in
switch response.result {
case .success(let value):
observable.on(.next(value))
observable.onCompleted()
case .failure(let error):
observable.onError(error)
self.errorHandle(error: error, statusCode: response.response?.statusCode)
}
}
return Disposables.create()
}
}
// エラー処理
func errorHandle(error: Error, statusCode: Int?) {
if statusCode == 401 {
// 共通エラー処理をここに記載します。
}
}
}
// API処理
class API {
// ホスト名
private static let Host = "http://localhost:3000/api/v1"
// 共通ヘッダー
static let CommonHeaders:HTTPHeaders = [
"Authorization": "Test",
"Version": Bundle.main.infoDictionary!["CFBundleShortVersionString"]! as! String,
"Accept": "application/json"
]
// リクエスト処理の生成
fileprivate class func createRequest(router:Router, parameters: Parameters? = nil) -> Alamofire.DataRequest {
return Alamofire.request("\(Host)\(router.url())",
method:router.method(),
parameters: parameters,
encoding: JSONEncoding.default,
headers: API.CommonHeaders).validate()
}
}
github "ReactiveX/RxSwift"
github "Alamofire/Alamofire" ~> 4.4
github "Hearst-DD/ObjectMapper" ~> 2.2
github "tristanhimmelman/AlamofireObjectMapper" ~> 4.0
{
"id": 1,
"name": "hoge"
},
{
"id": 2,
"name": "foo"
}
API.Users.get(1).request().subscribe(onNext: { (user:Company) in
DebugLog("id = \(user.id)")
}).addDisposableTo(disposeBag)
"users": [
{
"id": 1,
"name": "hoge"
},
{
"id": 2,
"name": "foo"
}
]
API.createRequest(router: self, parameters: parameters)
.responseArray { (keyPath: "users", response: DataResponse<[T]>)
return Observable.create { (observable: AnyObserver<T>) in
...
return Disposables.create()
}
import Foundation
import ObjectMapper
class User: Mappable {
var id = 0
var name = ""
required init?(map: Map) {}
// Mappable
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
}
}
extension API {
enum Users: Router {
// データ一覧取得
case list
// データ一件取得
case get(Int)
// ルーティングはここで行います。
func url() -> String {
switch self {
case .list:
return "/users"
case .get(let id):
return "/users/\(id)"
}
}
// methodも上記同様に定義できます。未定義の場合はgetが使われます。
}
}
class UsersViewController: UIViewController {
// APIの解放で使います。わからない人はこのまま実装すればOKです。
let disposeBag = DisposeBag()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 一覧取得
// パラメータをつけたい場合はparametersに[String:String]で定義。なくても動きます。
API.Users.list.request(parameters: nil).subscribe(onNext: { (users:[User]) in
for user in users {
DebugLog("id = \(user.id)")
}
}).addDisposableTo(disposeBag)
// 一件のデータ取得
API.Users.get(1).request().subscribe(onNext: { (user:User) in
DebugLog("id = \(user.id)")
}).addDisposableTo(disposeBag)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment