3

Here's the code:

func makePOSTCall(endpoint: String, languageName: String) {
    guard let url = URL(string: endpoint) else {
        print("Could not create URL.")
        return
    }

    let requestLang: [String: Any] = ["name": languageName]
    let requestBody = try? JSONSerialization.data(withJSONObject: requestLang)

    var urlRequest = URLRequest(url: url)
    urlRequest.httpBody = requestBody
    urlRequest.httpMethod = "POST"
    let session = URLSession.shared
    let task = session.dataTask(with: urlRequest) {

        data, response, error in
        guard let data = data, error == nil else {
            print(error?.localizedDescription ?? "No data")
            return
        }

        let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
        if let responseJSON = responseJSON as? [String: Any] {
            print(responseJSON)
        }

    }
    task.resume()
}

This sends a {"name": "Go"} JSON dictionary to Flask. Flask is supposed to append the language name to an array and return the full array in the response. Now, this works when I send the request manually, so it's not Flask's error. But when I send the above from iOS, I get request.json == None in the flask console. Clearly, I'm sending an empty body, but I shouldn't be. Any idea where I went wrong?

I call the function as

@IBAction func pressedMakePOSTCall(_ sender: UIButton) {

    makePOSTCall(endpoint: "http://127.0.0.1:5000/lang", languageName: "Go")

}

I tried adding a trailing slash, just get a 404 in the console. The only question similar to mine that I've found is this: How to make HTTP Post request with JSON body in Swift and my code is basically identical.

T. Spikes
  • 141
  • 1
  • 11
  • Have you checked, does the JSONSerialization succeed, is `requestBody` not `nil`? You also shouldn't define `requestBody` as `[String:Any]`, since its only value is clearly of type `String`, so `requestBody` should be `[String:String]`, but there is no need for the type annotation anyways. – Dávid Pásztor Aug 15 '17 at 11:06
  • `this works when I send the request manually` What do you mean by that? Also, could you check the value of `requestBody`? – Larme Aug 15 '17 at 11:10
  • This behaviour could have different issues. I think you should also validate if your tranfered data has the right encoding. And you should try to set your content type. Because if the expected content type is for instance `x-www-form-urlencoded` and you are sending `application/json` the server does not receive or process the data as you would expect. – weissja19 Aug 15 '17 at 12:35
  • @DávidPásztor, print(requestBody) gives Optional(13 bytes). Shouldn't it have thrown if the serialization failed? – T. Spikes Aug 15 '17 at 12:39
  • No, since you are using `try?`, which just return `nil` if an error occurs. An error is only thrown if you use `try` embedded inside a `do-catch` block or you get an unrecoverable runtime exception if you use `try!` and an error is thrown. However, if your data is not nil, then the problem might be with your encoding. Please include a working request from another source, such as Postman so we can see what is different here. – Dávid Pásztor Aug 15 '17 at 12:40
  • @DávidPásztor already fixed, see my answer below. But thank you so much for your replies, I'm pretty new to swift as you can see. – T. Spikes Aug 15 '17 at 12:48

2 Answers2

7

@weissja19 was correct, I needed to set content type to application/json. Adding

urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")

fixed the error. Now the code works as I expected.

P.S. I couldn't catch it because I use the app Paw for testing, which sets content type automatically.

T. Spikes
  • 141
  • 1
  • 11
1

You might want to do it manually:

urlRequest.httpBody = "name=\(languageName)".data(using: .utf8)

Use JSONSerialization will make your POST body like {"name":"abc"} which might not be supported by your server

Tj3n
  • 9,837
  • 2
  • 24
  • 35
  • That's exactly what I want to do. Flask server parses json when it receives it in the request body. I've sent manual requests with Paw and they go through just fine. – T. Spikes Aug 15 '17 at 12:15