0
2

More than 1 year has passed since last update.

【Swift】Alamofireでカスタムレスポンスを作成する

Posted at

はじめに

AlamofireでAPIを叩いてresponseDecodable(of: StatusesShow.self)でデコードされた結果を受け取る。
今までこの方法で使っていました。
この時返ってくる値はResult<StatusesShow, AFError>です。

例えばTwitterのAPIを叩いたとしましょう。
TwitterErrorを使いたいと思うとこのように美しくない実装になります。

AF.request(url, method: .get, headers: headers).responseDecodable(of: StatusesShow.self) { response in
    switch response.result {
    case .success(let data):
        print(data)
    case .failure(_):
        guard let data = response.data, let localRateLimited = String(data: data, encoding: .utf8) else { return }
        do {
            let twitterError = try JSONDecoder().decode(TwitterError.self, from: data)
            print(twitterError)
        } catch {
            print(localRateLimited)
        }
    }
}

Result<StatusesShow, TwitterError>で返ってきてほしい!!!

カスタムレスポンスを作成して美しいコードにします。

やりかた

ResponseSerializerを使用します。

import Alamofire
import Foundation

final class TwitterDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
    private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: JSONDecoder())
    private lazy var errorSerializer = DecodableResponseSerializer<TwitterError>(decoder: JSONDecoder())

    public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Result<T, ErrorCode> {

        guard error == nil else { return .failure(.code000) }

        guard let response else { return .failure(.code000) }

        do {
            // 成功
            let result = try successSerializer.serialize(request: request, response: response, data: data, error: nil)
            return .success(result)
        } catch {
            // 失敗
            let result = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
            return .failure(result.errors[0].code)
        }
    }
}

extension DataRequest {
    @discardableResult func responseTwitterDecodable<T: Decodable>(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated), of t: T.Type, completionHandler: @escaping (Result<T, ErrorCode>) -> Void) -> Self {
        return response(queue: .main, responseSerializer: TwitterDecodableResponseSerializer<T>()) { response in
            switch response.result {
            case .success(let result):
                // 成功 or 失敗
                completionHandler(result)
            case .failure(_):
                // 想定外のレスポンス
                guard let data = response.data, let localRateLimited = String(data: data, encoding: .utf8) else { return }
                print(localRateLimited)
            }
        }
    }
}

使い方

はい〜、美しい

AF.request(url, method: .get, headers: headers).responseTwitterDecodable(of: StatusesShow.self) { response in
    switch response {
    case .success(let data):
        print(type(of: data)) // StatusesShow
    case .failure(let error):
        print(type(of: error)) // TwitterError
    }
}

おわり

めっちゃ綺麗になりました!

参考記事

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2