Swift Post Request Don't Work

Swift POST Request not working

I figured it out, I had to add in this in my swift file:

request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

URLRequest POST doesn't work in Swift 5. There may be a problem with the server?

Nothing wrong here.

  • Status 200
  • code doesn’t test for error but I bet it’s nil
  • Print of response is what you should expect
  • Print JSON prints a json object.

You should be happy. Or What would you expect?

No response from swift post request

Update 1

Okay, after reading your comment, heres whats going on, the program is ending before your code is even being executed. A simple way to see this is if you add a break point in your code.

You can use a semaphore to block the current thread and wait for your URL session to finish.

A dispatch semaphore is an efficient implementation of a traditional
counting semaphore. Dispatch semaphores call down to the kernel only
when the calling thread needs to be blocked. If the calling semaphore
does not need to block, no kernel call is made.
Apple

This code will do what you want it to.

var sema = DispatchSemaphore( value: 0 )
let session = URLSession.shared
let url = URL(string: "https://fmsauth.scania.com/auth/S2S4DA/ClientId2Challenge")!

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let payload = Data("clientId=cgoxyBxM1KVO3pLm5J7VgDVxlP7_33BpPlPXeIaSmoLsTZq8DfyM1svTwi-SU7KJKBRN4V3mIsV7pNNEg610Xw".utf8)

let task = session.uploadTask(with: request, from: payload) { data, response, error in

if let data = data, let dataString = String(data: data, encoding: .utf8) {
print(dataString)
sema.signal()
}

if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}

task.resume()
sema.wait()

First post

Your code works, I think you need to enable the transport. Add this to info.plist

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>somethingthatshouldntworkyourdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>

Response

Code 200

{"challenge":"eeABaKaf2ZdhPEVQ4ru2S58_j37VLetM3pryIP8uiXk"}
<NSHTTPURLResponse: 0x600003be73e0> { URL: https://fmsauth.scania.com/auth/S2S4DA/ClientId2Challenge } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Length" = (
182
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Wed, 15 Jan 2020 21:12:31 GMT"
);
Server = (
"Microsoft-IIS/8.5"
);
"Set-Cookie" = (
"BIGipServerfmsauth.scania.com_https_pool=!c+BZzlVtgeV0E7NCFLoANbUAp39TaIJT2kJgIPLs8cCAJ4R4UMhNbWVOiSnTd/Cx6OuLMGUfIpke3g==; path=/; Httponly; Secure"
);
Vary = (
"Accept-Encoding"
);
"X-HandlingWebServer" = (
sesofms9112
);
"X-Powered-By" = (
"ASP.NET"
);
"owin.RequestId" = (
"4dbeb043-0e55-4972-b955-45c28f94aa77"
);
} }

HTTP Post Request data could not be read Swift 3

A few observations:

  1. You shared PHP that is using $_POST. That means it's expecting x-www-form-urlencoded request. So, in Swift, you should set Content-Type of the request to be application/x-www-form-urlencoded because that's what you're sending. Likewise, in Swift, the Accept of the request should be application/json because your code will "accept" (or expect) a JSON response.

  2. The values string you've supplied has a space in it. There can be no spaces in the key-value pairs that you send in a x-www-form-urlencoded request. (Note, if you have any non-alphanumeric characters in your values key pairs, you should be percent encoding them.)

  3. In your Swift error handler, in addition to printing the error, you might want to try converting the data to a String, and looking to see what it says, e.g.

    if let string = String(data: data!, encoding: .utf8) {
    print(string)
    }
  4. You might also want to look at response and see what statusCode it reported. Having done that, you subsequently told us that it reported a statusCode of 500.

    Status code 500 means that there was some internal error in the web service. (The code is 200 if successful.) This is generally a result of some error with the request not being handled correctly. For example, if the request neglected to format the request correctly and the web service doesn't anticipate/catch that, or if there was some other internal error on the web server, you could get 500 error code. For list of status codes, see http://w3.org/Protocols/rfc2616/rfc2616-sec10.html.

  5. If the text in the body of the response from your web service is not illuminating, you might want to turn on error reporting (see How to get useful error messages in PHP? or How do I catch a PHP Fatal Error) and then look at the body of the response again. For example, you might include the following in your PHP:

    <?php

    function __fatalHandler() {
    $error = error_get_last();
    //check if it's a core/fatal error, otherwise it's a normal shutdown
    if ($error !== NULL && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING))) {
    header("Content-Type: application/json");
    $result = Array("success" => false, "error" => $error);
    echo json_encode($result);
    die;
    }
    }
    register_shutdown_function('__fatalHandler');
    // the rest of your PHP here
    ?>

Can't figure out swift POST request error

It looks like your server is returning loginResult instead of serverResponse. Could you try

if let decodedResponse = try? JSONDecoder().decode(loginResult.self, from: data) {
print(decodedResponse)
DispatchQueue.main.async {
self.results = [decodedResponse]
}
return
}

(iOS / Swift) Simple Post Request with Key-Value Failed, But Succeeded using Postman

Your content type is application/x-www-form-urlencoded, but you're setting the body as JSON instead of URL-encoded parameters. The way your HTTP body looks with the way you have it now is something like:

{"uname":"21120113120038","pass":"123456"}

...but you want it to look like this:

uname=21120113120038&pass=123456

So, replace this line:

guard let httpBody = try? JSONSerialization.data(withJSONObject: parameter, options: []) else {return}

...with something like this:

guard let httpBody = parameter.map({
[$0.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "",
$1.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""].joined(separator: "=")
}).joined(separator: "&").data(using: .utf8) else { return }

(However, I think that's a bit messy, so here are some extensions to clean it up somewhat:)

extension String {
var urlEncodedQueryKeyOrValue: String {
return addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""
}
}

extension Dictionary where Key == String, Value == String {
var wwwFormURLEncodedString: String {
return map { "\($0.urlEncodedQueryKeyOrValue)=\($1.urlEncodedQueryKeyOrValue)" }.joined(separator: "&")
}
}

And then you'd use it like this:

[...]
guard let httpBody = parameter.wwwFormURLEncodedString.data(using: .utf8) else { return }
request.httpBody = httpBody
[...]

HTTP Request in Swift with POST method

The key is that you want to:

  • set the httpMethod to POST;
  • optionally, set the Content-Type header, to specify how the request body was encoded, in case server might accept different types of requests;
  • optionally, set the Accept header, to request how the response body should be encoded, in case the server might generate different types of responses; and
  • set the httpBody to be properly encoded for the specific Content-Type; e.g. if application/x-www-form-urlencoded request, we need to percent-encode the body of the request.

E.g., in Swift 3 and later you can:

let url = URL(string: "https://httpbin.org/post")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
let parameters: [String: Any] = [
"id": 13,
"name": "Jack & Jill"
]
request.httpBody = parameters.percentEncoded()

let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else { // check for fundamental networking error
print("error", error ?? URLError(.badServerResponse))
return
}

guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}

// do whatever you want with the `data`, e.g.:

do {
let responseObject = try JSONDecoder().decode(ResponseObject<Foo>.self, from: data)
print(responseObject)
} catch {
print(error) // parsing error

if let responseString = String(data: data, encoding: .utf8) {
print("responseString = \(responseString)")
} else {
print("unable to parse response as string")
}
}
}

task.resume()

Where the following extensions facilitate the percent-encoding request body, converting a Swift Dictionary to a application/x-www-form-urlencoded formatted Data:

extension Dictionary {
func percentEncoded() -> Data? {
map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
}

extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="

var allowed: CharacterSet = .urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}

And the following Decodable model objects facilitate the parsing of the application/json response using JSONDecoder:

// sample Decodable objects for https://httpbin.org

struct ResponseObject<T: Decodable>: Decodable {
let form: T // often the top level key is `data`, but in the case of https://httpbin.org, it echos the submission under the key `form`
}

struct Foo: Decodable {
let id: String
let name: String
}

This checks for both fundamental networking errors as well as high-level HTTP errors. This also properly percent escapes the parameters of the query.

Note, I used a name of Jack & Jill, to illustrate the proper x-www-form-urlencoded result of name=Jack%20%26%20Jill, which is “percent encoded” (i.e. the space is replaced with %20 and the & in the value is replaced with %26).


See previous revision of this answer for Swift 2 rendition.



Related Topics



Leave a reply



Submit