iosswiftmoya

How to intercept Moya request and return failure response without sending the request at all


I'm using Moya library to handle networking layer, and I already have a custom plugin that add an authentication token to the header.

What I want to do is to make this plugin cancel the request and return a failure response (or throw an error) if the token is not available yet.

P.S. I extended the protocol TargetType to add extra variable that indicates if the target needs authentication or not, so I need to access these data to determine if the authentication token is needed in the header or not.

this is a snapshot of my custom plugin:

struct AuthTokenPlugin: PluginType {
    let tokenClosure:()->String?

    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        guard let target = target as? AuthorizebleTargetType, target.needsAuth else {
            return request
        }

        guard let token = tokenClosure() else {
            // Here where a failure response will be triggered or an error should be thrown  
            return ......
        }

        var request = request
        request.addValue( "Token " + token, forHTTPHeaderField:"Authorization")
        return request
    }
}

P.S.2: throwing an error is not a good practice and it is not possible because the enclosing function "prepare(_:target:)" is not declared 'throws'.


Solution

  • I don't think that we can implement such logic with usage of protocol TargetType in cause his methods don't return Bool values and are not throw-marked.

    Take a look at MoyaProvider init parameters. There is a requestClosure param in it. You can copy-paste and replace this parameter's default implementation with your own implementation which will check authorization header of Endpoint.

    Default implementation of this closure:

    final class func defaultRequestMapping(for endpoint: Endpoint, closure: RequestResultClosure) {
            do {
                let urlRequest = try endpoint.urlRequest()
                closure(.success(urlRequest))
            } catch MoyaError.requestMapping(let url) {
                closure(.failure(MoyaError.requestMapping(url)))
            } catch MoyaError.parameterEncoding(let error) {
                closure(.failure(MoyaError.parameterEncoding(error)))
            } catch {
                closure(.failure(MoyaError.underlying(error, nil)))
            }
        }
    

    UPD with my comment:

    I suggest to check that if Endpoint has header with key “Authorization”, but it’s value is empty string, then call closure parameter with .failure case in requestClosure