Un exemple de client API Moya + RxSwift (Swift5)

supposition

Par défaut, Swift utilise la classe URLSession pour le traitement des communications, mais Moya est une bibliothèque qui lui sert de wrapper.

Cela semble être une méthode standard sur le site de développement car elle peut être écrite facilement. Particulièrement pratique lorsqu'il est combiné avec RxSwift.

Pour le moment, il est préférable de connaître la classe URLSession dans une certaine mesure, donc les débutants doivent d'abord s'habituer à URLSession, puis passer à Moya et se rendre compte qu'elle peut être utilisée facilement.

Officiel Client API réalisé avec Swift4 + Moya + RxSwift + Codable

L'ensemble

APIClient.swift

APIClient.swift


final class APIClient {
    private init() {}
    static let shared = APIClient()

    // MARK: - Private

    private let provider = MoyaProvider<MultiTarget>()

    private let stubProvider = MoyaProvider<MultiTarget>(stubClosure: MoyaProvider.immediatelyStub)

    // MARK: - Public

    func request<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        Single<G.Reponse>.create { observer in
            self.makeRequest(request)
                .subscribe(onSuccess: { response in
                    observer(.success(response))
                }, onError: { error in
                    //Gestion des erreurs, etc. que vous souhaitez faire en commun tout au long du projet
                    observer(.error(error))
                })
        }
    }

    func makeRequest<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        provider.rx
            .request(MultiTarget(request))
            .flatMap({ response -> Single<Response> in
                //Vérification de l'en-tête de la réponse
                return Single.just(try response.lookingAllHeaderFields())
            })
            .flatMap { response -> Single<Response> in
                //Vérifier le code d'erreur
                return Single.just(try response.successfulStatusCodesPolicy())
        }
        .map(G.Reponse.self, failsOnEmptyData: false)
    }

    func requestStub<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        Single<G.Reponse>.create { observer in
            self.makeRequestStub(request)
                .subscribe(onSuccess: { response in
                    observer(.success(response))
                }, onError: { error in
                    if let error = error as? MoyaError {
                    //Gestion des erreurs, etc. que vous souhaitez faire en commun tout au long du projet
                    observer(.error(error))
                })
        }
    }

    func makeRequestStub<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        stubProvider.rx
            .request(MultiTarget(request))
            .flatMap({ response -> Single<Response> in
                //Vérification de l'en-tête de la réponse
                return Single.just(try response.lookingAllHeaderFields())
            })
            .flatMap { response -> Single<Response> in
                //Vérifier le code d'erreur
                return Single.just(try response.successfulStatusCodesPolicy())
        }
        .map(G.Reponse.self, failsOnEmptyData: false)
    }
}

ApiTargetType.swift

ApiTargetType.swift


import Foundation
import Moya

protocol ApiTargetType: TargetType {
    associatedtype Response: Codable
}

extension ApiTargetType {

    /// The target's base `URL`.
    var baseURL: URL {
        URL(string: "\(URLs.baseURL)")!
    }
}

Commentaire

Le client API est un objet singleton

APIClient.swift


final class APIClient {
    private init() {}
    static let shared = APIClient()
Utilisation de MultiTarget

--- MultiTarget est utilisé pour que différents types de TargetType puissent être affectés à MoyaProvider. En conséquence, le côté utilisateur du client API peut éviter de passer le TargetType au MoyaProvider via les génériques et peut masquer l'existence du MoyaProvider du côté utilisateur.

APIClient.swift


private let provider = MoyaProvider<MultiTarget>()
Utilisation du plugin

APIClient.swift


private let provider = MoyaProvider<MultiTarget>(plugins: [FooPlugin()])

Plugin.swift


/// A Moya Plugin receives callbacks to perform side effects wherever a request is sent or received.
///
/// for example, a plugin may be used to
///     - log network requests
///     - hide and show a network activity indicator
///     - inject additional information into a request
public protocol PluginType {
    /// Called to modify a request before sending.
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest

    /// Called immediately before a request is sent over the network (or stubbed).
    func willSend(_ request: RequestType, target: TargetType)

    /// Called after a response has been received, but before the MoyaProvider has invoked its completion handler.
    func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType)

    /// Called to modify a result before completion.
    func process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError>
}
Utilisation de stubProvider

APIClient.swift


    private let stubbingProvider = MoyaProvider<MultiTarget>(stubClosure: MoyaProvider.immediatelyStub) //.delayed(seconds: 1.0)Etc. sont également possibles
Vérification de la réponse

APIClient.swift


    // MARK: - Public

    func request<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        Single<G.Reponse>.create { observer in
            self.makeRequest(request)
                .subscribe(onSuccess: { response in
                    observer(.success(response))
                }, onError: { error in
                    //Gestion des erreurs, etc. que vous souhaitez faire en commun tout au long du projet
                    observer(.error(error))
                })
        }
    }

    func makeRequest<G: ApiTargetType>(_ request: G) -> Single<G.Reponse> {
        provider.rx
            .request(MultiTarget(request))
            .flatMap({ response -> Single<Response> in
                //Vérification de l'en-tête de la réponse
                return Single.just(try response.lookingAllHeaderFields())
            })
            .flatMap { response -> Single<Response> in
                //Vérifier le code d'erreur
                return Single.just(try response.successfulStatusCodesPolicy())
        }
        .map(G.Reponse.self, failsOnEmptyData: false)
    }

Type de cible

S'il y a quelque chose qui est commun à l'ensemble du projet (généralement, l'URL de base, etc.), c'est une bonne idée de le sortir et de créer un protocole TargetType.

python


protocol ApiTargetType: TargetType {
    associatedtype Response: Codable
}

extension ApiTargetType {

    /// The target's base `URL`.
    var baseURL: URL {
        URL(string: "\(URLs.baseURL)")!
    }
}

Exemple d'utilisation

python


    func fetchData() -> Single<HogeEntity> {
        return APIClient.shared.request(HogeTargetType())
    }

HogeTargetType.swift


import Foundation
import Moya

struct HogeTargetType: ApiTargetType {
    typealias Response = HogeEntity

    var path: String {
        return "/hogehoge/"
    }

    var method: Moya.Method {
        return .get
    }
    var task: Task {
        let param: [String: Any] = [
            "id": id
        ]

        return .requestParameters(parameters: param, encoding: URLEncoding.default)
    }
    var headers: [String: String]? {
        [
            "Content-Type": "application/json",
            "x-auth-token": API.authToken
        ]
    }

       var sampleData: Data {
        let path = Bundle.main.path(forResource: "Hoge", ofType: "json")!
        guard let file = FileHandle(forReadingAtPath: path) else {
            return Data()
        }

        return file.readDataToEndOfFile()
    }

    // MARK: - Arguments

    /// ID
    var id: String {
        return DataManager.shared.id ?? ""
    }

    init() {}
}

HogeEntity.swift


struct HogeEntity: Codable {
   let fuga: String

Hoge.json


{
   "fuga": "test"
}

Matériel de référence

Client API réalisé avec Swift4 + Moya + RxSwift + Codable Moya/Examples/Multi-Target/ViewController.swift

Recommended Posts

Un exemple de client API Moya + RxSwift (Swift5)
[swift5] Essayez de créer un client API avec différentes méthodes
Utilisez Swift pour trouver une approximation de sinx
Trouver une approximation de cosx avec Swift
Un exemple simple du modèle MVC
J'ai créé un client API pour Nature Remo