Syncronous http request Swift - swift

I'm using Alamofire to make a GET request. It's working just fine but it's request() method runs asynchronously, I cannot know which line is called first. I just want to know how can I make an exactly same GET request using synchronous manner.
Alamofire.request(.GET, "http://localhost:2403/postedjob", parameters: ["$limit": 2, "$sort": ["id":"+1"]])
.responseJSON { _, _, JSON, _ in
println(JSON)
}

This may not be the answer that you are expecting.. but I believe it to be the correct answer. Do not do http requests in a synchronous way. You should do this asynchronously and use protocols or completion blocks to execute code after the request has finished.

Related

Swift 3 Uploading data to a server with Alamofire

I'm currently using alamofire to request data from a web service.Everything works great but I have a doubt about how to upload data to my server with the method get.
Example of web service --> http://www.google.com/id=2&name=trump&message=fakenews
I tried to use the traditional alamofire.request("weberservice") but It didn't work.
How do I send this information using alamofire?
What you want to do is make a POST request. This sends data to the server.
What you will do is use the request method, but add an additional argument for the HTTP method:
Alamofire.request("<YOUR-URL>", method: .post)
The Alamofire docs here talk about passing the data to the server when you make the POST request. You basically add a 3rd argument with the dictionary:
let parameters: Parameters = ["foo": "bar"]
// All three of these calls are equivalent
Alamofire.request("https://httpbin.org/get", parameters: parameters)
// https://httpbin.org/get?foo=bar
From the Alamofire docs

NSURLSession data task response handling

I am currently working on implementing a networking model that communicates with a REST API through HTTP in Swift using NSURLSession class.
For preparing the request, I use this code:
var request = URLRequest(url: requestURL) // url is "http://somethingsomething...
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = body
Now, I am sending the requests that way:
session.dataTask(with: request) { data, response, error in
// Parse the data, response and error
}.resume()
My problem is that I want to check the httpStatusCode of the response in order to inform about possible errors, however, the response inside the completion block is of type URLResponse, not HTTPURLResponse. This means that I have to cast the response to the type HTTPURLResponse. So far I've thought of two ways to approach it - first is to add another error scenario which would handle the "couldn't cast to HTTPURLResponse" scenario, the other way is to simply force the cast to HTTPURLResponse. The first option seems better but it could be just adding some useless code, because maybe the cast will always succeed?
So basically, my question is - can I be sure that, if I send the requests to a HTTP server, the response will always be of HTTPURLResponse type? Or do I have to implement the code that handles a situation where the response object is of a different type or is a nil?
Also, I think it would be good to mention that in my implementation if the completion block returns error that is not nil, the flow will return before trying to cast anything.
I believe this is what you need.
session.dataTask(with: request) { data, response, error in
// Parse the data, response and error
if let httpResponse = response as? HTTPURLResponse {
//here it is
print(httpResponse.statusCode)
}
}.resume()
I have never had the cast fail to my knowledge. I am not sure why URLResponse and HTTPURLResponse aren't merged into one class, but HTTPURLResponse is a subclass that the response always can be cast to as far as my knowledge goes.

How to make sure that an Alamofire request runs?

I copy-pasted the first example of the Alamofire readme (at fa3c6d0) into main.swift:
import Foundation
import Alamofire
Alamofire.request("https://httpbin.org/get").responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
print("Done")
When I run this, all I get is Done, then the application terminates.
While I see here that I can pick a dispatch queue, this answer seems to suggest that I shouldn't have to.
Anyway, having had a similar issue with "basic" requests I tried the same solution but to no avail: the application now blocks. So, apparently, Alamofire has a different default than URLSession and wants to use the main thread.
What is the best way to have a request executed (and waited for) in an application like this?
We need to do two things.
Execute the request in the background.
Block the main thread until the request is done, i.e. the completion handler ran.
My original code does neither.
The first item is achieved by using .response(queue: DispatchQueue(label: "some-name")) (or one of its variants).
Waiting can be done in several ways.
Using a flag and active waiting, as shown here (won't scale to more than one request).
Use active waiting with countdown latch as shown here (works for multiple requests).
Use DispatchSemaphore as seen e.g. here.
And probably many more.

Preventing NSURLSession default HTTP headers

I'm trying to craft a very specific HTTP request to a server (ie. defining the exact set of HTTP headers), but NSURLSession keeps "helpfully" inserting a bunch of HTTP headers like Accept, Accept-Language and Accept-Encoding.
Consider the following playground (Swift 2.x) which sends a request to a service that just echos the HTTP headers that were sent:
import Foundation
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let url = NSURL(string: "http://httpbin.org/headers")!
let request = NSMutableURLRequest(URL: url, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 30000)
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let session = NSURLSession(configuration: configuration)
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
XCPlaygroundPage.currentPage.finishExecution()
}
task.resume()
You can see that there are three Accept headers being sent. How can I prevent that?
I've tried setting the header using request.setValue(nil, forHTTPHeaderField: "Accept-Language") but that gets ignored. Tried setting it to "", but no good. I've also tried manipulating the HTTPAdditionalHeaders property on NSURLSessionConfiguration, but no love.
How do I get NSURLSession to not be quite so helpful?
I doubt what you're asking for is possible. NSURLSession (and NSURLConnection) automatically provide a number of headers, and that's one of them.
There's also no valid reason to remove them. All three of those headers have been part of the spec since the original HTTP/0.9 spec (https://www.w3.org/Protocols/HTTP/HTRQ_Headers.html). There's absolutely no excuse for any server not either handling those correctly or ignoring them outright.
With that said, if you provide the wrong value for those fields (and the default may be wrong), the server may refuse to give you results. To solve that problem, first figure out what type of data the server is actually going to provide, and specify that value in the Accept header instead of the default.
For example, you might set Accept to "application/json" or one of the other variants (What is the correct JSON content type?) if you're expecting JSON data.
That said, if you really must avoid having those headers sent, you can always open a socket, construct the request manually, and send it. Assuming the server doesn't require chunked encoding, it is pretty easy to do. (Chunked encoding, however, is a horror of Herculean proportions, so if your server sends that back, you'll pretty much have to resort to adding libcurl into your project and using that to make requests instead.)

Can Alamofire call a different response serializer depending on the content-type of the response?

Depending on its mood and information we send in the request, our server might send back an empty-bodied 204 response with content type text/plain or something else like a 400-series response with an application/json body detailing the error. How should we handle this?
We thought something like this:
Alamofire.request(request)
.responseString({ (request, response, string, error) -> Void in
// Happy dance
})
.responseSwiftyJSON({ (request, response, json, error) -> Void in
// Parse the error out of the json response and inform the user
})
... but it seems all the chained response handlers are executed. Is there a way to say "only call this one for a specific error type" or "only call this one for a specific response code"?
Are we missing something about how Alamofire is meant to work?