Home > Mobile >  Convert CURL to Swift
Convert CURL to Swift

Time:02-14

I need to convert the following curl call of Microsoft Azure Cloud to Swift:

curl -X POST "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn" -H "Ocp-Apim-Subscription-Key: <client-secret>" -H "Content-Type: application/json; charset=UTF-8" -d "[{'Text':'Hello, what is your name?'}]"

I need to convert a JSON call of curl to Swift. The problem is I have no experience with JSON calls and don't know how to include headers, a body and parameters. So I tried the following code:


let apiKey = "..."
let location = "..."

class AzureManager {
    
    static let shared = AzureManager()
    
    func makeRequest(json: [String: Any], completion: @escaping (String)->()) {
        
        guard let url = URL(string: "https://api.cognitive.microsofttranslator.com/translate"),
              let payload = try? JSONSerialization.data(withJSONObject: json) else {
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue(apiKey, forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
        request.addValue(location, forHTTPHeaderField: "Ocp-Apim-Subscription-Region")
        request.addValue("application/json", forHTTPHeaderField: "Content-type")
        request.addValue("NaiVVl3DEFG3jdE5DE1NFAA6EABC", forHTTPHeaderField: "X-ClientTraceId")
        request.httpBody = payload

        URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard error == nil else { completion("Error::\(String(describing: error?.localizedDescription))"); return }
            guard let data = data else { completion("Error::Empty data"); return }
            
            let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]

            if let json = json,
               let choices = json["translations"] as? [String: Any],
               let str = choices["text"] as? String {
                completion (str)
            } else {
                completion("Error::nothing returned")
            }
            
        }.resume()
    }
}

And then call it like this:

let jsonPayload = [
           "api-version": "3.0",
           "from": "en",
           "to": "it",
           "text": "Hello"
           ] as [String : Any]
   
AzureManager.shared.makeRequest(json: jsonPayload) { [weak self] (str) in
     DispatchQueue.main.async {
           print(str)
     }
}

Well, the errors I get are:

    Optional(["error": {
        code = 400074;
        message = "The body of the request is not valid JSON.";
    }])

And:

Error::nothing returned

Here are the Docs of Microsoft Azure Translator: https://docs.microsoft.com/de-de/azure/cognitive-services/translator/reference/v3-0-translate

CodePudding user response:

Let's analyze your cURL command, let's make it more readable with breaking line. If you want to make it working as such in Terminal.app, just add \ at the end of the line.

curl \
-X POST \ 
"https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn" \
-H "Ocp-Apim-Subscription-Key: <client-secret>" \ 
-H "Content-Type: application/json; charset=UTF-8" \ 
-d "[{'Text':'Hello, what is your name?'}]"

-H: Set with addValue(_,forHTTPHeaderField:) -d: Set it with httpBody = The long URL, that's request.url

There are two main differences between the cURL command and the URLRequest you mode.

First, you did mix payload & URL settings.

url should be "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh-Hans&toScript=Latn", not "https://api.cognitive.microsofttranslator.com/translate", you put api-version, to, toScript (that one is missing by the way) inside httpBody. Put them into the URL instead. You can use URLQueryItem to format them correctly. See related question.

Now, once you fix that, there is a second issue:

[{'Text':'Hello, what is your name?'}], I'll by pass the strange fact that it's using single quotes, but, here JSON is an array at top level, not a dictionary. Also, it's Text, not text (it might be case sensitive).

If you want to see what you are sending in httpBody, do not hesitate to do:

if let jsonStr = String(data: request.httpBody ?? Data(), encoding: .utf8) {
    print("Stringified httpBody: \(jsonStr)")
}

So fix your parameters until it matches the on in the working cURL command. As said, it's an array, not a dictionary.

Finally, avoid using try?, please do proper do/try/catch because if it fails, at least you need to know about it.
No need to use .allowFragments if you don't expect a JSON String at top level. Here you are expecting a Dictionary.
And I'd recommand to use Codable now in Swift 4 instead of JSONSerialization.

Edit: Seeing the doc, as you mixed the parameters/query, keep in mind: "Query Parameters", that's for URLQueryItems and it's in the URL. Request Body: That's for the httpBody.

  • Related