0
votes

I'm trying to learn to call API with/without library. But the problem here confuses me.

I have params like this:

let parameters: [String:String] =
            ["key":"MY_KEY" ,
             "q":sourceText,
             "source": sourceLanguage),
             "target": target)]

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

I make a post call like this:

Alamofire.request(urlString, method: HTTPMethod.post, parameters: parameters, headers: headers)
                .responseJSON{ response in
                    guard response.result.error == nil else {
                        print("error calling POST on /todos/1")
                        print(response.result.error!)
                        return
                    }
                    // make sure we got some JSON since that's what we expect
                    guard let json = response.result.value as? [String: Any] else {
                        print("didn't get todo object as JSON from API")
                        print("Error: \(response.result.error)")
                        return
                    }

By this I get an error 403, saying that I do not have a valid API key (I tested the key with postman, and it is okay).

After many efforts, I have to change the code like this

let stringparams = "key=MY_KEY&q=\(sourceText)&source=\(sourceLanguage)&target=\(target)"
request.httpBody = stringparams.data(using: String.Encoding.utf8)

and using this: Alamofire.request(request) it works! I'm using Google Cloud Translation api. And the web use a REST api as said here: https://cloud.google.com/translate/docs/reference/translate

So why can't I use params as dictionary, but using the string (like formdata) will work here?

My guess is Alamofire didn't make the right BODY for the request from the parameters because other arguments is okay. But I don't know why. And I think Google should accept a json params as they mentioned, in stead of using form data? I did try the original method, but it didn't work with JSON.

2
The Alamofire.request method has the parameter encoding, which you may need to customise if you have a non-standard way of passing parameters to your request (which it seems like you do).Guy Kogus
In this version I forgot that I deleted the encoding: JSONEncoding.default. But it didn't work, neither. Earlier it is like this: Alamofire.request(urlString, method: HTTPMethod.post, parameters: parameters, encoding: JSONEncoding.default, headers: headers)Dong Manh
You may have to create your own implementation of ParameterEncoding.Guy Kogus
@GuyKogus Sorry. Can you explain to me how to implement the param encoding here? I thought I have to provide the params as exactly as required in the Alamofire request method?Dong Manh

2 Answers

0
votes

From what actually works for you it looks like you need to encode the parameters in the same style as a query. Try this:

struct ParameterQueryEncoding: ParameterEncoding {
    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var request = try urlRequest.asURLRequest()
        request.httpBody = parameters?
            .map { "\($0)=\($1)" }
            .joined(separator: "&")
            .data(using: .utf8)
        return request
    }
}

You should then be able to perform the original call that you had before:

Alamofire.request(urlString,
                  method: HTTPMethod.post,
                  parameters: parameters,
                  encoding: ParameterQueryEncoding(),
                  headers: headers)
    .responseJSON { response in
        ...
}
0
votes

Try by using JSON encoding. Make sure you have removed ) from dictionary.

Alamofire.request(URL, method: method, parameters: parameters, encoding: JSONEncoding.default, headers: headers)