Moya: Plugins doesn't work with GET requests

Hello

I use Moya/RxSwift 2.0.8 and I’m trying to use plugins to implement authorization token in HTTP headers

For example API:

import Moya

enum Api {
    case getRequest
}

extension Api: AuthorizedTargetType {
    /// The target's base `URL`.
    var baseURL: URL { return URL(string: "http://url.com")! }
    
    /// The path to be appended to `baseURL` to form the full `URL`.
    var path: String {
        switch self {
        case .getRequest:
            return "/api/v1/services/book"
        }
    }
    
    /// The HTTP method used in the request.
    var method: Moya.Method {
        switch self {
        case .getRequest:
            return .get
        }
    }
    
    /// The parameters to be incoded in the request.
    var parameters: [String: Any]? {
        switch self {
        case .getRequest:
            return nil
        }
    }
    
    /// The method used for parameter encoding.
    var parameterEncoding: ParameterEncoding {
        return URLEncoding.default
    }
    
    /// Provides stub data for use in testing.
    var sampleData: Data {
        switch self {
        case .getRequest:
            return "{\"records\": [{\"id\": 3,\"price\": 5000,\"service\": {\"id\": 2,\"title\": \"Предпусковые подогреватели\"},\"created\": \"2017-02-13T11:26:19.125243Z\",\"modified\": \"2017-02-13T12:25:01.328032Z\",\"discount\": 0.2,\"date\": \"2017-02-13\",\"user\": 2}],\"total\": 5000,\"discount_total\": 1000}".utf8Encoded
        }
    }
    
    /// The type of HTTP task to be performed.
    var task: Task {
        switch self {
        default:
            return .request
        }
    }
    
    /// Whether or not to perform Alamofire validation. Defaults to `false`.
    var validate: Bool {
        return false
    }
    
    var needsAuth: Bool {
        switch self {
        case .getRequest:
            return true
        default:
            return true
        }
    }
}


// MARK: - Helpers
private extension String {
    var urlEscaped: String {
        return self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
    }
    
    var utf8Encoded: Data {
        return self.data(using: .utf8)!
    }
}

With Plugin:

import Moya

struct AuthPlugin: PluginType {
    let token: String?
    
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        guard let token = token,
            let target = target as? AuthorizedTargetType,
            target.needsAuth
            else {
                return request
        }
        
        var request = request
        request.addValue("Token " + token, forHTTPHeaderField: "Authorization")
        return request
    }
}

protocol AuthorizedTargetType: TargetType {
    var needsAuth: Bool { get }
}

And working code

    let provider = RxMoyaProvider<Api>(
        plugins: [
            AuthPlugin(token: "eb1b505e863token6274bdfbe23925d223"),
            NetworkLoggerPlugin(verbose: true)])

    provider.request(.getRequest)
            .debug()
            .filterSuccessfulStatusCodes()
            .subscribe(onNext: { (response) in
                print(response)
            }, onDisposed: {
            })

In log we can see this situation:

["Moya_Logger: [13/02/2017 18:40:06] Request: http://url.com/api/v1/services/book"]
["Moya_Logger: [13/02/2017 18:40:06] Request Headers: [\"Authorization\": \"Token eb1b505e8634d19a2ece786274bdfbe23925d223\"]"]
["Moya_Logger: [13/02/2017 18:40:06] HTTP Request Method: GET"]
["Moya_Logger: [13/02/2017 18:40:07] Response: <NSHTTPURLResponse: 0x78e81ad0> { URL: http://url.com/api/v1/services/book/ } { status code: 401, headers {\n    Allow = \"GET, OPTIONS\";\n    Connection = \"keep-alive\";\n    \"Content-Type\" = \"application/json\";\n    Date = \"Mon, 13 Feb 2017 15:48:35 GMT\";\n    Server = \"nginx/1.9.9\";\n    \"Transfer-Encoding\" = Identity;\n    Vary = Accept;\n    \"Www-Authenticate\" = Token;\n    \"X-Frame-Options\" = SAMEORIGIN;\n} }"]
["{\"detail\":\"Учетные данные не были предоставлены.\"}"]

But token is not present in the headers

Hypertext Transfer Protocol
    GET /api/v1/services/book/ HTTP/1.1\r\n
    Host: url.com\r\n
    Connection: keep-alive\r\n
    Accept: */*\r\n
    Accept-Encoding: gzip;q=1.0, compress;q=0.5\r\n
    User-Agent: moyaTest/1.0 (test.moyaTest; build:1; iOS 10.2.0) Alamofire/4.3.0\r\n
    Accept-Language: ru-RU;q=1.0, en-RU;q=0.9\r\n
    \r\n
    [Full request URI: http://url.com/api/v1/services/book/]
    [HTTP request 2/2]
    [Prev request in frame: 94914]
    [Response in frame: 94930]

But POST requests are working properly.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

@scottrhoyt Good idea on using https://httpbin.org 🙌

As seen in Charles:

REQUEST CONTAINING AUTHORIZATION

GET //get HTTP/1.1
Host	httpbin.org
Connection	keep-alive
Accept	*/*
User-Agent	moyaTest/1.0 (eu.indevgroup.moyaTest; build:1; iOS 10.2.0) Alamofire/4.3.0
Accept-Language	en;q=1.0
Authorization	Token eb1b505e8634d19a2ece786274bdfbe23925d223
Accept-Encoding	gzip;q=1.0, compress;q=0.5

And response from https://httpbin.org/get

{
	"args": {},
	"headers": {
		"Accept": "*/*",
		"Accept-Encoding": "gzip;q=1.0, compress;q=0.5",
		"Accept-Language": "en;q=1.0",
		"Authorization": "Token eb1b505e8634d19a2ece786274bdfbe23925d223",
		"Host": "httpbin.org",
		"User-Agent": "moyaTest/1.0 (eu.indevgroup.moyaTest; build:1; iOS 10.2.0) Alamofire/4.3.0"
	},
	"origin": "201.47.197.212",
	"url": "https://httpbin.org/get"
}

I could not reproduce the case of not seeing the field in the request but seeing it in the response.