はじめに
SwiftでAlamofireを利用する際,毎回Modelを利用するのは面倒ですよね。
Codableを利用して簡単に書きましょう!
Alamofireを利用した baseRequest()
の作成
ここでは,typealias
を利用して,T
に様々な型が入るようにしたクロージャを定義し,
Decodable
をクロージャで引き受けつつ通信を行うbaseRequest()
を作成しています。
import Alamofire
class Foo {
/// Success handler
public typealias SuccessHandler<T> = (_ model: T) -> Void
/// Failure handler
public typealias FailureHandler = (_ error: Error) -> Void
/**
Alamofire Request
- Parameters:
- url: API URL
- method: HTTP method
- parameters: Query parameters
- success: Success handler
- failure: Failure handler
*/
func baseRequest<T: Decodable>(_ url: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
success: SuccessHandler<T>?,
failure: FailureHandler?) {
Alamofire.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers)
.responseData { response in
switch response.result {
case .success:
guard let success = success, let data = response.data else { return }
let decoder: JSONDecoder = JSONDecoder()
guard let model = try? decoder.decode(T.self, from: data) else { return }
success?(model)
case .failure(let error):
failure?(error)
}
}
}
}
guard let model = try? decoder.decode(T.self, from: data) else { return }
部分では,デコード処理を記述していますが,
引数success: SuccessHandler<T>
のT
の型によってT.self
が変更され,デコード先が様々な型を許容することを示しています。
利用方法
以下のようなModelを定義してみました。
public struct FooModel: Codable {
public let bar: String
}
ここで新たに SuccessHandler
に FooModel
を代入した request
methodを立てます。
func request(_ url: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
success: SuccessHandler<FooModel>?,
failure: FailureHandler?) {
self.baseRequest(url,
method: method,
parameters: parameters,
success: success,
failure: failure)
}
これにより, request()
経由で取得したResponseはFooModel
にパースされて処理できるようになります。
呼び出しは以下の通りです。
self.request(url, success: { fooModel in
print(fooModel.bar)
})
デコードのテストを書く
せっかく便利になったので,Codableなstructがきちんとデコードされるかをテストしましょう。
Codableはしっかり定義しないと全てがnilとなってしまいます。テストは必要ですよね?
import XCTest
@testable import Foo
final class FooTests: XCTestCase {
var foo: Foo!
override func setUp() {
super.setUp()
self.foo = Foo()
}
func decode<T: Decodable>(_ url: String, parameters: Parameters?, model: T.Type) {
let expect: XCTestExpectation = self.expectation(description: url)
let success: Foo.SuccessHandler<T> = { model in
expect.fulfill()
XCTAssertNotNil(model)
}
let failure: Foo.FailureHandler = { error in
expect.fulfill()
XCTFail(error.localizedDescription)
}
self.foo.baseRequest(url, success: success, parameters: parameters, failure: failure)
self.wait(for: [expect], timeout: 10)
}
}
呼び出しは以下のように書きます。
func testDecodeFoo() {
decode(url, parameters: parameters. model: FooModel.self)
}
これでModelが増えても簡単に書けるようになりました。
それでは良いAlamofireライフを!