Alamofireのresponse serializerをカスタマイズ

2426 ワード

AlamofireのDataRequestクラスは、バイナリ・データ、文字列、json、プロパティ・リストの解析に便利な方法(内部では実際にResponse Serializerが使用されている)を提供しています.サービス側が返すデータ・フォーマットに対して、独自のResponse Serializerを定義します.
サーバが返すデータフォーマットは次のようになります.
{
    "code": 0,
    "datas": {
        "name": "Jack",
        "age": 13
    },
    "message": ""
}

ここでdatas,messageに対応するデータは空である可能性があり,このフォーマットに対してResponse Serializerを定義する.
バイナリデータからデータモデルまで、Swift 4に内蔵されているJSOnDecoderをそのまま使って解析するので、定義したモデルはDecodableプロトコルに従う必要があります(下記のコード、私はサボるために直接Codableを書きました).
struct Response: Codable {
    let code: Int
    let datas: T?
    let message: String?
}

struct Person: Codable {
    let name: String
    let age: Int
}

extension DataRequest {
    static func customResponseSerializer(type: T.Type) -> DataResponseSerializer {
        return DataResponseSerializer(serializeResponse: { (request, response, data, error) -> Result in
            guard error == nil else {
                return .failure(error!)
            }
            let result = Request.serializeResponseData(response: response, data: data, error: nil)
            switch result {
            case .success(let validData):
                do {
                    let entity = try JSONDecoder().decode(T.self, from: validData)
                    return .success(entity)
                } catch {
                    return .failure(error)
                }
            case .failure(let error):
                return .failure(error)
            }
        })
    }

    @discardableResult
    func responseCustomObject(queue: DispatchQueue? = nil,
                                type: T.Type,
                                completion: @escaping (DataResponse) -> Void) -> Self {
        return response(queue: queue, responseSerializer: Alamofire.DataRequest.customResponseSerializer(type: type), completionHandler: completion)
    }
}

使うときは、これでいいです:
Alamofire.request("http://mall.cnrmall.com/api/app/version_check").responseCustomObject(type: Response.self) { (response) in
    switch response.result {
    case .success(let value):
        print(value)
    case .failure(let error):
        print("error: \(error.localizedDescription)")
    }
}