I have standard code in Swift like below:
private func testFormUrlEncodedRequest() {
let headers = [
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
]
let postData = NSMutableData(data: "user_id=5874ae8ae9a98c2d6cef1da8".data(using: String.Encoding.utf8)!)
postData.append("&offset=0".data(using: String.Encoding.utf8)!)
postData.append("&limit=20".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://www.example.com/endpoint")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
ViewController.log(request: request as! URLRequest)
print((request as URLRequest).curlString)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
ViewController.log(data: data, response: response as? HTTPURLResponse, error: error)
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
}
But the problem is that it hangs on, and then request times out with error. REST API is written in Node.js and gets error in body-parser module like request aborted.
I can make successfully the same request with POSTMAN or curl (from Terminal) and I get correct response.
Code on server which I have no access to seems to be also rather standard, and was used in previous projects where it was tested to work correctly with iOS apps.
I have no idea why this request goes ok with POSTMAN and doesn't work with URLSession in Swift.
Any help will be beneficial.
Here is error message printed to console I am getting:
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x6000013196e0
{Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://example.com/api/endpoint, NSErrorFailingURLKey=http://example.com/api/endpoint,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
This request gives error in such cases: 1. form-url-encoded params in HTTP request body 2. raw application/json params in HTTP request body 3. It works if params are passed in query params 4. It crashes with request aborted error on server side (body-parser module) 5. node.js uses standard app.use()
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
It uses http without SSL but in Info.plist there is App Transport Security > Allow Arbitrary Loads set to YES etc.
UPDATE: This is error on server side
BadRequestError: request aborted
at IncomingMessage.onAborted (/Users/michzio/Click5Interactive/Reusable Parts/NetworkApi/node_modules/raw-body/index.js:231:10)
at emitNone (events.js:86:13)
at IncomingMessage.emit (events.js:188:7)
at abortIncoming (_http_server.js:381:9)
at socketOnClose (_http_server.js:375:3)
at emitOne (events.js:101:20)
at Socket.emit (events.js:191:7)
at TCP.Socket._destroy.cb._handle.close [as _onclose] (net.js:510:12)
Node.js Test Code:
const express = require('express');
const port = 9001;
const app = express();
const bodyParser = require('body-parser');
var todos = [{id:1, title:'buy the milk'}, {id:2, title:'rent a car'}, {id:3, title:'feed the cat'}];
var count = todos.length;
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json());
app.get('/test', (request, response) => {
console.log("-----")
console.log(request.params);
console.log(request.body);
console.log(request.query);
console.log("-----")
response.status(200).json( todos );
});
app.listen(port);
It seems that GET + query params works, and POST + body params (url-from-encoded or application/json) also works correctly.
So it doesn't work for GET body params url-form encoded and GET body params application/json. Is it some limitation of URLSession/URLRequest in Swift. POSTMAN can pass params in body with GET and server receives it in request.body !
UPDATE 2!
Yes, it seems that in Android/Kotlin with OkHttpClient there even is not possible to define Request Body with GET method. And there is also this error. Maybe this only works with POSTMAN and curl, and should not be used in real application scenario to join GET and body params.
public fun makeNetworkRequest(v: View) {
object : Thread() {
override fun run() {
val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{ \"test\" : \"nowy\", \"test2\" : \"lol\" }")
/*
val request = Request.Builder()
.url("http://10.0.2.2:9001/test")
.get()
.addHeader("Content-Type", "application/json")
.build()
*/
val mySearchUrl = HttpUrl.Builder()
.scheme("http")
.host("10.0.2.2")
.port(9001)
.addPathSegment("test")
.addQueryParameter("q", "polar bears")
.build()
val request = Request.Builder()
.url(mySearchUrl)
.addHeader("Accept", "application/json")
.method("GET", body)
.build()
val response = client.newCall(request).execute()
Log.d("RESPONSE", response.toString())
}
}.start()
}