#はじめに
AlamofireをラップしたMoyaというライブラリを使ってみました。
RxSwift拡張もあるとのことなので、
Moya+RxSwift+Codableということで備忘も兼ねて記事にしました。
Moya:https://github.com/Moya/Moya
#準備
今回はCocoapodsを使いました。
pod 'Moya/RxSwift'
#APIの定義
MoyaではTargetTypeプロトコルに準拠したenumでAPIを定義します。
今回は簡単なログインAPIな想定です。
enum Login {
// パスごとにcaseを切り分ける
case login(id: String, pass: String)
}
extension Login: TargetType {
// ベースのURL
var baseURL: URL {
return URL(string: "https://hogehoge.com")!
}
// パス
var path: String {
switch self {
case .login:
return "/login"
}
}
// HTTPメソッド
var method: Moya.Method {
switch self {
case .login:
return .post
}
}
// スタブデータ
var sampleData: Data {
let path = Bundle.main.path(forResource: "login_stub", ofType: "json")!
return FileHandle(forReadingAtPath: path)!.readDataToEndOfFile()
}
// リクエストパラメータ等
var task: Task {
switch self {
case .login(let id, let pass):
return .requestParameters(parameters: ["id" : id, "pass": pass], encoding: URLEncoding.default)
}
}
// ヘッダー
var headers: [String: String]? {
return nil
}
}
MoyaではStubとしてローカルのjsonをレスポンスとして返すことが出来ます。
これが特に便利に感じました。
デコード用にDecodableに準拠したstructを定義します。
struct LoginResponse: Decodable {
let userId: String
}
#カスタム通信クラスを定義
MoyaはAlamofireをラップしているため、タイムアウト等を設定する場合には、
SessionManagerを別途カスタムする必要があります。
そのため、通信クラスであるMoyaProviderを継承したCustomMoyaProviderクラスを定義します。
final class CustomMoyaProvider<T: TargetType>: MoyaProvider<T> {
public init(endpointClosure: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,
requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,
stubClosure: @escaping StubClosure = MoyaProvider.neverStub,
callbackQueue: DispatchQueue? = nil,
plugins: [PluginType] = [],
trackInflights: Bool = false) {
let sessionManager: SessionManager = {
let configuration = URLSessionConfiguration.default
// タイムアウトを設定する
configuration.timeoutIntervalForRequest = 30
return SessionManager(configuration: configuration)
}()
super.init(endpointClosure: endpointClosure,
requestClosure: requestClosure,
stubClosure: stubClosure,
callbackQueue: callbackQueue,
manager: sessionManager,
plugins: plugins,
trackInflights: trackInflights)
}
}
#API通信呼び出し
MoyaProviderが破棄されてしまうとSubscribeも止まってしまうため、
プロパティとして定義します。
前述したStubを利用する設定をCustomMoyaProvider定義時に渡します。
neverStub...通常のAPI通信
immediatelyStub...Stubを返す
delayedStub(x)...x秒後にStubを返す
private let loginProvider = CustomMoyaProvider<Login>(stubClosure: MoyaProvider.delayedStub(2))
private let disposeBag = DisposeBag()
通信します。
レスポンスをmapでdecodeし、subscribeに流します。
loginProvider.rx
.request(.login(id: "id", pass: "pass"))
.map { (response) -> LoginResponse? in
return try? JSONDecoder().decode(LoginResponse.self, from: response.data)
}.subscribe(onSuccess: { (response) in
if let unwrappedResponse = response {
print(unwrappedResponse)
} else {
print("error")
}
}, onError: { (error) in
print("error")
})
.disposed(by: disposeBag)
通信部もシンプルでよいです。
以上となります。
何かございましたら指摘してくださると大変喜びます。