WilliamD47
WilliamD47

Reputation: 183

Getting bad request error with alamofire JSON request

I have been converting this curl syntax

curl -L -X POST 'https://driver-vehicle-licensing.api.gov.uk/vehicleenquiry/v1/vehicles' \-H 'x-api-key: REPLACE WITH YOUR API KEY' \-H 'Content-Type: application/json' \-d '{"registrationNumber": "TE57VRN"}'

into Swift with Alamofire and have got this syntax

guard let url = URL(string: "https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles") else { return }

                    let headers : HTTPHeaders = [
                            "x-api-key": "mykey",
                            "Content-Type": "application/json"

                        ]

                    let params: Parameters = [
                            "registrationNumber" : "myreg"
                        ]

                    AF.request(url, method: .post, parameters: params, encoding: URLEncoding(destination: .httpBody), headers: headers).responseJSON(completionHandler: { response in
                        print(response)
                    })

However, I have got the output

success({
errors =     (
            {
        code = ENQ103;
        detail = "Invalid format for field - vehicle registration number";
        status = 400;
        title = "Bad Request";
    }
);

Please could someone explain what I have done wrong. Thanks

Upvotes: 0

Views: 522

Answers (2)

Larme
Larme

Reputation: 26096

You have a working curl command, small (or big) tip: AlamoFire can print the request as a curl command!

In "one step":

AF.request(url, method: .post,
           parameters: params,
           encoding: URLEncoding(destination: .httpBody),
           headers: headers)
   .cURLDescription(calling: { curlCommand in
    print("curlCommand1: \(curlCommand)")
}).responseJSON(completionHandler: { response in
    print(response)
})

In "two steps", if you prefer to separate your calls and not chain them all:

let request = AF.request(url, method: .post,
                         parameters: params,
                         encoding: URLEncoding(destination: .httpBody),
                         headers: headers)
request.cURLDescription { curlCommand in
    print("curlCommand2: \(curlCommand)")
}

request.responseJSON(completionHandler: { response in
    print(response)
})

And you should have output:

curl -v \
    -X POST \
    -H "Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8" \
    -H "User-Agent: Alamofired/1.0 (...; build:1; iOS 14.5.0) Alamofire/5.4.0" \
    -H "Accept-Language: en;q=1.0, fr-US;q=0.9" \
    -H "Content-Type: application/json" \
    -H "x-api-key: mykey" \
    -d "registrationNumber=myreg" \
    "https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles"

Now, if we compare with yours:

curl \ 
-L \
-X POST \
'https://driver-vehicle-licensing.api.gov.uk/vehicleenquiry/v1/vehicles' \
-H 'x-api-key: REPLACE WITH YOUR API KEY' \
-H 'Content-Type: application/json' \
-d '{"registrationNumber": "TE57VRN"}'

I added some \ to make it sill valid...

We shouldn't care about the order, the "Accept-Language", "User-Agent", "Accept-Encoding" headers that are added with Alamofire shouldn't be an issue.
Try your command with no -L parameter maybe to check if it's "important" (if it's --location).
And then, the difference is with the data paramater (-d). Once is JSON, the other is URL encoded.

Then, let's see your code, and URLEncoding(destination: .httpBody) might be the culprit. Using JSONEncoding.default instead will work.

Now, if you didn't have had the curl command, just by seeing your code, I spotted it. If you think about it:

You are saying there that you will provide the parameter in body following the JSON protocol.

let headers : HTTPHeaders = ["Content-Type": "application/json"]

And later, you used URL Encoding protocol.

URLEncoding(destination: .httpBody)

Doesn't make sense, right? You're contradicting yourself.

Upvotes: 0

Palash Bansal
Palash Bansal

Reputation: 827

The API expects the parameters to be sent as JSON, but you are sending as URL encoded. Try using JSONParameterEncoder.default as the encoder instead of URL encoding. Check Usage from the docs: POST request with JSON Parameters

let parameters: Parameters = [
                            "registrationNumber" : "myreg"
                        ]

AF.request(url, method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)

Upvotes: 1

Related Questions