0

I am trying to send HTTP request with POST method in a command line app. Using JSON as body of the request. I am using session.uploadTask to send this request and use JSON data serialised from simple Dictionary. Maybe I missed something but it doesn't work. I even tried to write my request to console and it looks good -> it is the same format as iTranslate API wants.

//creating new session
let session = URLSession.shared
let url = URL(string: "https://api.itranslate.com/translate/v1")!

//setting httpMethod to POST
var request = URLRequest(url: url)
request.httpMethod = "POST"

//setting header
request.setValue("application/json", forHTTPHeaderField: "content-type")

//dictionary with json
let json = ["key": "...", "source": ["dialect":"en", "text": "How are you?"], "target": ["dialect": "es"]] as [String : Any]

//serialization from json to jsonData
let jsonData = try! JSONSerialization.data(withJSONObject: json, options: [])

let task = session.uploadTask(with: request, from: jsonData) { data, response, error in
    
    if let data = data, let dataString = String(data: data, encoding: .utf8) {
        print(dataString)
    }
}

task.resume()
Rob
  • 415,655
  • 72
  • 787
  • 1,044
Aidn
  • 18
  • 5
  • 2
    Define “it doesn't work”. What is in the body of the response? What was the HTTP status code? – Rob Dec 09 '20 at 15:42
  • In the body is: {"key": "83fcbf65-1d2c-4051-b37f-5935e8fc7768", "source": {"dialect": "en", "text": "How are you?"}, "target": {"dialect": "es"}} – Aidn Dec 09 '20 at 15:49
  • @Rob There is no error. status response is 200 – Leo Dabus Dec 09 '20 at 15:50
  • @Aidn your actual response is `{"source": {"text": "How are you?", "dialect": "en"}, "target": {"dialect": "es", "text": "\u00bfC\u00f3mo est\u00e1s?"}, "times": {"total_time": 0.041}} ` – Leo Dabus Dec 09 '20 at 15:51
  • I.e., it's telling you “¿Cómo estás?”, which is correct. – Rob Dec 09 '20 at 15:53
  • How you get the actual response @LeoDabus ? – Aidn Dec 09 '20 at 15:53
  • I don't understand “it immediately stops”. Is this in a playground, or an app? – Rob Dec 09 '20 at 15:53
  • Just a command line app – Aidn Dec 09 '20 at 15:54
  • 1
    A command line app isn't going to wait for the `URLSession` background request to finish. That closure is called asynchronously (i.e. later). – Rob Dec 09 '20 at 15:55
  • I mean it should print a response should't it? – Aidn Dec 09 '20 at 15:55
  • (response as? HTTPURLResponse)?.statusCode – Leo Dabus Dec 09 '20 at 15:55
  • @Larme yeah. Thank you. It prints the response. – Aidn Dec 09 '20 at 16:02
  • That's the suggested comment pointed by Rob https://stackoverflow.com/questions/65219810/post-request-with-urlsession-in-swift?noredirect=1#comment115302479_65219810 I just search a similar question for it. – Larme Dec 09 '20 at 16:03

1 Answers1

1

In most apps, there is a “run loop” that is constantly running, responding to user interaction, keeping the app alive until the user explicitly terminates it. In that scenario, we can initiate the asynchronous network request, confident that the run loop is keeping our app alive, and when the network response comes in, our completion handler closure is called.

In a command line app, on the other hand, when it gets to the end of the code, the app simply terminates, never giving the asynchronous network request a chance to respond, and the closure will never be called.

You can, however, have the command line app wait for the request to finish before terminating, e.g.

let semaphore = DispatchSemaphore(value: 0)

let task = session.uploadTask(with: request, from: jsonData) { data, response, error in
    if let data = data, let dataString = String(data: data, encoding: .utf8) {
        print(dataString)
    }
    semaphore.signal()
}

task.resume()
semaphore.wait()

Now, this technique (waiting on the main thread, thereby blocking that thread) is a very bad practice in standard apps, because it will block the main thread while the network request is running. In a typical app, blocking the main thread would freeze the UI, offering a substandard user experience (and the OS might even kill the app for not being responsive). We generally would never block the main thread.

But in a command line app, where you often don't worry about a graceful and responsive UI, blocking the main thread is less of an issue and the above can keep the app alive while the network request is running.

Rob
  • 415,655
  • 72
  • 787
  • 1,044