Home > Mobile >  Alamofire - add both query parameter and body
Alamofire - add both query parameter and body

Time:02-14

I am trying to send a request that should contain both URL parameters and request body in JSON. Backend doesn't recognize the request and returns 400 status code.

This is how I tried to solve the problem

enum MyRequestsRouter: URLRequestConvertible {

    case RequestA(paramA: String, bodyInJsonString: String),
         RequestB(paramB: String)

    var baseURL: URL {
        URL(string: "http://127.0.0.1:8080")!
    }

    var method: HTTPMethod {
        switch self {
        case .RequestA: return .post
        case .RequestB: return .get
        }
    }

    var path: String {
        switch self {
        case .RequestA: return "/api/a"
        case .RequestB: return "/api/b"
        }
    }

    var parameters: Parameters? {
        switch self {
        case .RequestA(let paramA, let bodyInJsonString):
            return [
                "paramA": paramA
            ]

        case .RequestB(let paramB):
            return ["paramB": paramB]

        default:
            return nil
        }
    }

    func asURLRequest() throws -> URLRequest {
        let url = baseURL.appendingPathComponent(path)
        var request = URLRequest(url: url)
        request.method = method

        switch self {
        case let .RequestA(paramA, bodyInJsonString):
            // here I am specifying `paramA` value
            request = try URLEncoding.default.encode(request, with: parameters)

            // here body is already serialized to Json
            request.httpBody = Data(bodyInJsonString.utf8)
            request.setValue("application/json", "Content-Type")

        case let .RequestB(paramB):
            request = try URLEncoding.default.encode(request, with: parameters)
            
        }

        return request
    }

}

And this is how I am making API call

let json: Data = try JSONEncoder().encode(notSerializedBodyObject)
let jsonString = String(data: json, encoding: .utf8)

AF.request(MyRequestsRouter.RequestA(paramA: "paramA", bodyInJsonString: jsonString!)).response { response in
            print("Request: \(response.request)")
            print("Response: \(response.response)")
            print("Error: \(response.error)")
            
            // etc
            }
            
}

As you can see the request URL is supposed to be
http://127.0.0.1:8080/api/a?paramA=paramA plus request body in JSON. But response is 400 Bad request.

How to properly configure Alomofire?

CodePudding user response:

Alamofire's URLEncoding has an initializer that gets destination as parameter. Based on documentation:

Destination defining where the encoded query string will be applied. .methodDependent by default.

By default .methodDependent case checks the HTTP method of the request and only on .get, .head and .delete requests it encodes the passed parameters in the URL.

Given that fact, you never see paramA in your request (not even in the body) because you override it in the following line:

// here body is already serialized to Json
request.httpBody = Data(bodyInJsonString.utf8)

So, instead of using the default URLEncoding, you can simply call URLEncoding's initializer directly passing as destination the .queryString case like this:

// here I am specifying `paramA` value
request = try URLEncoding(destination: .queryString).encode(request, with: parameters)

// here body is already serialized to Json
request.httpBody = Data(bodyInJsonString.utf8)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

That way you will have a request with paramA in the URL and your JSON as a body.

  • Related