Crear plugin para Moya Swift – iOS

Moya es un framework que nos ayuda a crear una capa extra en nuestras aplicaciones donde manejamos todo lo relacionado a llamadas http que hace nuestra aplicacion, es un framework bastante capaz y con un sin numero de buenas caracteristicas, entre ellas el poder configurar componentes (plugins).

public protocol PluginType {
    /// #1 Called to modify a request before sending.
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest

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

    /// #3 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)

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

Al final solo son 4 metodo que estaremos modificando a nuestra conveniencia, imaginemos que queremos agregar un token de authenticacion a cada request tendriamos que hacerlo antes de enviar el request por lo que podriamos implementarlo tanto el metodo prepare como en el metodo willSend, en caso de querer configurar un logger podriamos utilizar el metodo didReceive

  1. prepare: Este metodo es utilizando para configurar nuestro request, agregar algun header o modificar alguna configuracion a este.
  2. willSend: Este metodo sera llamado justo antes de ejecutar el request, por lo que podriamos utilizarlo para nosotros ejecutar algun comportamiento que queramos.
  3. didReceive: Este método es llamado una vez se complete la peticion http
  4. process: Este método es util para configurar la data que estaremos retornando.

El próximo ejemplo es un Plugin simple para hacer logging (imprimir) de las respuestas de nuestras peticiones HTTP, lo que me motiva a realizar este plugin es por el hecho de que el plugin nativo de Moya para este propósito en si no satisface mis necesidades y lo veo poco extensible (retornaba mucha información).

class LogPlugin: PluginType {
  func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
    switch result {
    case .success(let response):
      print("✓ \(response.statusCode):", response.request?.url?.absoluteString ?? "", "")
    case .failure(let error):
      print("Fail request", error.errorDescription ?? "")
    }
  }
}

Para usar nuestro plugin solo tendremos que a la hora de instanciar nuestor provider tendremos que agregarle un parametro extra que sera una lista de plugins:

let service = MoyaProvider<IPService>(plugins: [LogPlugin()])

Una vez realizado esto tendremos un resultado en consola como esto:

Moya log plugin response

Moya log plugin response

Podriamos mejorar nuestro plugin agregando un parametro en el constructor de este para que reciba una funciona que se encargara de generar el output y asi darle dinamicidad a este mensaje de log:

class LogPlugin: PluginType {
  let customFormatter: ((_ response: Response) -> String)
  
  init(with formatter: ((_ response: Response) -> String)? = nil) {
    if let formatter = formatter {
      customFormatter = formatter
    } else {
      customFormatter = LogPlugin.defaultFormatter
    }
  }

  private class func defaultFormatter(response: Response) -> String {
    return "✓ \(response.statusCode): \(response.request?.url?.absoluteString ?? "")"
  }

  func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
    switch result {
    case .success(let response):
      print(customFormatter(response))
    case .failure(let error):
      print("Fail request", error.errorDescription ?? "")
    }
  }
}

 

Referencia

Código completo: https://github.com/BlaShadow/MoyaPlugin