Moya: Add additional parameters to all requests

Created on 28 Nov 2017  路  13Comments  路  Source: Moya/Moya

Now we want to set a group of parameters for all requests NOT in headers,
Is there any way I can do it ?

question stale

Most helpful comment

Hey @aelam, sorry for the wait. Here is the endpointClosure that you could use to built your own version. Basically we don't really introduce a function to append parameters to _all_ targets as there are lots of undefined behaviors (as you will see in the code below). You need to have a domain specific knowledge to build your own version, where in older versions the behavior was mostly done by us under the hood and we had multiple issues asking why is something done this way and not another (in upload especially).

let endpointClosure1: MoyaProvider<HTTPBin>.EndpointClosure = { target in
    let additionalParameters = ["Additional": "Parameter"]
    let defaultEncoding = URLEncoding.default
    let task: Task

    switch target.task {
    case let .downloadDestination(destination):
        // First decision: what encoding to use when there wasn't one before
        task = .downloadParameters(parameters: additionalParameters, encoding: defaultEncoding, destination: destination)
    case .downloadParameters(var parameters, let encoding, let destination):
        additionalParameters.forEach { parameters[$0.key] = $0.value }
        task = .downloadParameters(parameters: parameters, encoding: encoding, destination: destination)
    case .requestCompositeData(let bodyData, var urlParameters):
        // Second decision: encode data and append the parameters there or append parameters to urlParameters?
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .requestCompositeData(bodyData: bodyData, urlParameters: urlParameters)
    case .requestCompositeParameters(let bodyParameters, let bodyEncoding, var urlParameters):
        // Third decision: where to append parameters here, body or url?
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: bodyEncoding, urlParameters: urlParameters)
    case let .requestData(data):
        task = .requestCompositeData(bodyData: data, urlParameters: additionalParameters)
    case let .requestJSONEncodable(encodable):
        // You would have to create data from `encodable`, encode it to JSON object, then append parameters
        // and make Data from it - and assign .requestData to the task
        task = target.task
    case .requestParameters(var parameters, let encoding):
        additionalParameters.forEach { parameters[$0.key] = $0.value }
        task = .requestParameters(parameters: parameters, encoding: encoding)
    case .requestPlain:
        task = .requestParameters(parameters: additionalParameters, encoding: defaultEncoding)
    case .uploadCompositeMultipart(let multipartData, var urlParameters):
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .uploadCompositeMultipart(multipartData, urlParameters: urlParameters)
    case let .uploadFile(url):
        // Another decision: where to add it with upload? in multipart data, or url?
        let data = Moya.MultipartFormData(provider: .file(url), name: "file")
        task = .uploadCompositeMultipart([data], urlParameters: additionalParameters)
    case let .uploadMultipart(multipartData):
        task = .uploadCompositeMultipart(multipartData, urlParameters: additionalParameters)
    }

    return Endpoint<HTTPBin>(url: URL(target: target).absoluteString, sampleResponseClosure: {.networkResponse(200, target.sampleData)}, method: target.method, task: task, httpHeaderFields: target.headers)
}

All 13 comments

What kind of parameters do you want to send? Query parameters?
You could look at this document and maybe use the endpointClosure or requestClosure.
Let us know if you need any help.

Thanks for your reply!!

endpointClosureand requestClosure are easy to append headers but hard to append parameters

If I want to insert a group of default parameters
Take platform=app1, appVersion=1.0 as an example.
If it's GET I will append to the end of URL, if it's POST I need encode the parameter. the ParameterEncode is same as the origin request which set in Target, JSON or urlencode or anything else

I've look into Moya a lot of times
Seems I have to override the Endpoint methods to append them
If I have to override the Endpoint, I have to give up Moya
Do you have any ideas?

extension Endpoint {
    /// Returns the `Endpoint` converted to a `URLRequest` if valid. Returns `nil` otherwise.
    public var urlRequest: URLRequest? {
        guard let requestURL = Foundation.URL(string: url) else { return nil }

        var request = URLRequest(url: requestURL)
        request.httpMethod = method.rawValue
        request.allHTTPHeaderFields = httpHeaderFields

        switch task {
        case .requestPlain, .uploadFile, .uploadMultipart, .downloadDestination:
            return request
        case .requestData(let data):
            request.httpBody = data
            return request
        case let .requestParameters(parameters, parameterEncoding):
            return try? parameterEncoding.encode(request, with: parameters)
        case let .uploadCompositeMultipart(_, urlParameters):
            return try? URLEncoding(destination: .queryString).encode(request, with: urlParameters)
        case let .downloadParameters(parameters, parameterEncoding, _):
            return try? parameterEncoding.encode(request, with: parameters)
        case let .requestCompositeData(bodyData: bodyData, urlParameters: urlParameters):
            request.httpBody = bodyData
            return try? URLEncoding(destination: .queryString).encode(request, with: urlParameters)
        case let .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: bodyParameterEncoding, urlParameters: urlParameters):
            if bodyParameterEncoding is URLEncoding { fatalError("URLEncoding is disallowed as bodyEncoding.") }
            guard let bodyfulRequest = try? bodyParameterEncoding.encode(request, with: bodyParameters) else { return nil }
            return try? URLEncoding(destination: .queryString).encode(bodyfulRequest, with: urlParameters)
        }
    }
}

In #1283 I talk about creating a plugin that allows parameters to be reused across multiple providers in point 5. This is not something I've tried to implement myself but it may be possible.

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

This issue has been auto-closed because there hasn't been any activity for at least 21 days. However, we really appreciate your contribution, so thank you for that! 馃檹 Also, feel free to open a new issue if you still experience this problem 馃憤.

Hey @aelam, you are right - it's not that simple to append parameters to all requests. Whenever I鈥檒l find time I will post a function that I was using to achieve this. Adding this to my todo-list as we speak. Sorry for the troubles!

I'll reopen so we can keep track 馃憤

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

I鈥檇 like this to remain open

Sent with GitHawk

Hey @aelam, sorry for the wait. Here is the endpointClosure that you could use to built your own version. Basically we don't really introduce a function to append parameters to _all_ targets as there are lots of undefined behaviors (as you will see in the code below). You need to have a domain specific knowledge to build your own version, where in older versions the behavior was mostly done by us under the hood and we had multiple issues asking why is something done this way and not another (in upload especially).

let endpointClosure1: MoyaProvider<HTTPBin>.EndpointClosure = { target in
    let additionalParameters = ["Additional": "Parameter"]
    let defaultEncoding = URLEncoding.default
    let task: Task

    switch target.task {
    case let .downloadDestination(destination):
        // First decision: what encoding to use when there wasn't one before
        task = .downloadParameters(parameters: additionalParameters, encoding: defaultEncoding, destination: destination)
    case .downloadParameters(var parameters, let encoding, let destination):
        additionalParameters.forEach { parameters[$0.key] = $0.value }
        task = .downloadParameters(parameters: parameters, encoding: encoding, destination: destination)
    case .requestCompositeData(let bodyData, var urlParameters):
        // Second decision: encode data and append the parameters there or append parameters to urlParameters?
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .requestCompositeData(bodyData: bodyData, urlParameters: urlParameters)
    case .requestCompositeParameters(let bodyParameters, let bodyEncoding, var urlParameters):
        // Third decision: where to append parameters here, body or url?
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: bodyEncoding, urlParameters: urlParameters)
    case let .requestData(data):
        task = .requestCompositeData(bodyData: data, urlParameters: additionalParameters)
    case let .requestJSONEncodable(encodable):
        // You would have to create data from `encodable`, encode it to JSON object, then append parameters
        // and make Data from it - and assign .requestData to the task
        task = target.task
    case .requestParameters(var parameters, let encoding):
        additionalParameters.forEach { parameters[$0.key] = $0.value }
        task = .requestParameters(parameters: parameters, encoding: encoding)
    case .requestPlain:
        task = .requestParameters(parameters: additionalParameters, encoding: defaultEncoding)
    case .uploadCompositeMultipart(let multipartData, var urlParameters):
        additionalParameters.forEach { urlParameters[$0.key] = $0.value }
        task = .uploadCompositeMultipart(multipartData, urlParameters: urlParameters)
    case let .uploadFile(url):
        // Another decision: where to add it with upload? in multipart data, or url?
        let data = Moya.MultipartFormData(provider: .file(url), name: "file")
        task = .uploadCompositeMultipart([data], urlParameters: additionalParameters)
    case let .uploadMultipart(multipartData):
        task = .uploadCompositeMultipart(multipartData, urlParameters: additionalParameters)
    }

    return Endpoint<HTTPBin>(url: URL(target: target).absoluteString, sampleResponseClosure: {.networkResponse(200, target.sampleData)}, method: target.method, task: task, httpHeaderFields: target.headers)
}

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

This issue has been auto-closed because there hasn't been any activity for at least 21 days. However, we really appreciate your contribution, so thank you for that! 馃檹 Also, feel free to open a new issue if you still experience this problem 馃憤.

same question, How to add common parameters?

Was this page helpful?
0 / 5 - 0 ratings