Network errors in Alamofire - ios

I am a newbie to iOS and using Alamofire in my app. Everything is working fine. Now I want to implement network errors. I have searched about it and here are my findings:
We can implment request timed out in the following way:
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 10
let urlVerifyEmail = ####
manager.request(urlVerifyEmail, method: .post, parameters: ["user_email" : email], encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: { response in
switch response.result {
case .success:
print (“success”)
case .failure(let serverError):
if (serverError._code == NSURLErrorTimedOut)
{
print(”Request timed out”)
}
else
{
print(”Error sending request to server”)
}
}
}
)
I have read there official docs too. However I am not having much clarity.
What does request timed out actually mean? Does it mean that the app is taking too long to send the request? or server is taking too long to send the response back?
What are other types or network errors in Alamofire? What if the connection wasn't successfully made? What if it broke while the request was getting sent? What if it broke while the response was coming back?
If error code for request timed out is -1001 then what are the codes for other network errors? In order to provide the users with the best experience, which is the best approach to cover all of network errors?

Related

iOS Alamofire - Streaming JSON lines first response issue

Using Alamofire 4.9.0.
I am trying to implement handling streaming APIs in JSON lines format. Here's how:
stream = Alamofire.request(url, method: HTTPMethod.get,
headers: TTSessionManager.headers)
.validate()
.stream(closure: { (data) in
// parsing JSON lines ...
})
.response(completionHandler: { (response) in
// error handling ...
})
Now the issue is that the first response takes some time to return. And when it does I get a couple of JSON lines in one big batch. After that stream continues to normally respond with a new JSON line per response coming through the stream.
Has anyone encountered this behaviour? I'm wondering wether there is some additional session or request setup needed in order for this to work normal (line per response) from the start. When inspecting the response.metrics after canceling the request a lot of the fields are null so I can't for sure say wether some of the initial connection steps are the issue:
(Domain Lookup Start) (null)
(Domain Lookup End) (null)
(Connect Start) (null)
(Secure Connection Start) (null)
(Secure Connection End) (null)
(Connect End) (null)
So the problem here was that the response header didn't have Content-Type set to application/json. When this header is not set properly, URLSession data task will buffer first 512 bytes of response.
More info can be found here: https://developer.apple.com/forums/thread/64875

Django CSRF Token Missing For iOS Post Request

Currently, I'm making an application that uses Django Rest Framework as my API and iOS (Swift) as my frontend using Alamofire for API calls. However, I've run into an issue with user authentication - whenever I try to make a POST request to login a user using Alamofire, I'm hit with this 403 error:
Here is my login setup with Alamofire:
func loginUser(data: Parameters) {
let finalUrl = self.generateUrl(addition: "auth/login/")
print(finalUrl)
let header: HTTPHeaders = [ "Accept": "application/json", "Content-Type" :"application/json"]
Alamofire.request(finalUrl,method: .post, parameters: data, encoding: JSONEncoding.default, headers: header).responseString { (response:DataResponse<String>) in
print(data)
switch(response.result) {
case .success(_):
if response.result.value != nil {
print(response.result.value!)
}
break
case .failure(_):
print(response.result.error!)
break
}
}
}
On the API side, the login I am using is the one provided by rest_framework.urls...
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework'))
While advice from similar posts has not resolved my issue, I believe my options are
a.) Exempt my views from requiring a CSRF token (I'm not sure if it's even possible in my case - my views are bundled with include() as part of the rest_framework.urls scheme so decorating with csrf_exempt cannot work)
b.)Obtain a CSRF Token for my POST requests somehow
While these are my ideas, I've yet to find an actual solution or method to implement them, so any help would be greatly appreciated!
Session Based Authentication is not required if you are building APIs for any mobile app. If you don't use cookies to manage your sessions, you don't need any CSRF protection. Am i wrong ? but anyway if you want to do so, pass #csrf_exempt
Instead of that it is better to use Token Based Authentication .You can check it here in the django -rest-api-docs . Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.

Alamofire 4 finish request in the background

I'm using alamorefire to make calls to an API, but I figured that if I put the app in the background, the call will pause and I don't want that. I want it to load and then, when I bring the app to the foreground, I can use the requested data on the UI. How can this be done? At the moment I just do plain requests like this:
Alamofire.request(url, method: .get, parameters: params, headers: header())
.responseJSON{response in switch response.result {
I've tried using the following alamofire configuration:
let configuration = URLSessionConfiguration.background(withIdentifier: "com.cmpny.myapp.background")
let manager = Alamofire.SessionManager(configuration: configuration)
manager.request(url, method: .get, parameters: params, headers: headers())
This gives me the following error:
Request failed with error: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=http://url, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=http://url}
You should use UIBackgroundTaskIdentifier for this purpose.
Apple doc:
https://developer.apple.com/reference/uikit/uiapplication/1623031-beginbackgroundtaskwithexpiratio
Similar question:
https://stackoverflow.com/a/31751337/1689376
Hope this helps ;)

Alamofire JSON POST result in Error: The network connection was lost

Several people get this error for different reasons. None of the answers I've found have solved my problem.
I use Timberjack to log my Alamofire requests.
All my GET requests work fine and I receive data in JSON.
My POSTs on the other hand works around 1 out 10 times every time if the POST includes a JSON body.
The server does not specify any Keep-Alive header.
Deployment target is iOS 9.0
This is my shared Manager with Timberjack:
class HTTPManager: Alamofire.Manager{
static let sharedManager: HTTPManager = {
let configuration = Timberjack.defaultSessionConfiguration()
let manager = HTTPManager(configuration: configuration)
return manager
}()
}
Defining the request:
let parameters: [String: AnyObject] = ["status":status]
request = HTTPManager.sharedManager.request(.POST, "\(baseURL)\(uri)", parameters: parameters, encoding: .JSON).validate()
Sending the request:
request!.responseJSON(queue: queue, options: .AllowFragments, completionHandler: { (response) in
//Handling the response
})
Most of the time the server receives an empty JSON body. But sometimes it does work and the body is received and the server responds with an OK. When it doesn't work I receive the error:
Error: The network connection was lost.
FAILURE: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
UserInfo={NSUnderlyingError=0x12fa47cb0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "The network connection was lost."
If someone can explain what's happening here I would be forever grateful :)
EDIT 1
We let the server respond every call with "Connection": "close" which did nothing to help the problem. The app always sends "Connection": "keep-alive" by default and it cannot be changed. Could this be the problem? That the app thinks the connection is open even though it's closed by the server? But even though you wait a few minutes it seems as though the POST call only works at random.
EDIT 2
Even when I wait 30 seconds between GET(s) and/or POST(s). GET always works. POST works at random (rarely). I get the -1005 error on most POSTs. Even though I get the network connection was lost error the server still receive my request but the JSON body is missing.
EDIT 3 - Ugly solution
In my response I check for the error code -1005, when I receive this error I just recreate the request and try again. This results in sending around 2-4 POST requests to the server where one POST works and the rest have empty JSON bodies.
Restart simulator or kill your app by throwing out from tasks.
Or check more solutions to this error code:
NSURLErrorDomain Code -1005 The network connection was lost

How to set body type to JSON in Alamofire?

I'm working online with different people from different projects who take care of backend API webservice. Usually I don't have problems with sending and receiving JSON, but this time, I can't seem to be able to send JSON properly to the server.
Usually I use Alamofire to receive and send JSON message, and the usual call go like this:
let param = populateParamWithDictionary();
let url = "https://www.example.com";
Alamofire.request(.POST, url, parameters: param, headers: nil)
.responseJSON { response in {
// take care of response here
}
But this time, I got project which the backend programmer requires me to use OAuth v2. So, let's say I've develop a function which already take care of getting the access_token string. The function now become like this:
let param = populateParamWithDictionary();
let url = "https://www.example.com";
let headers : Dictionary<String, String> = [
"Content-Type":"application/json",
"Authorization":"Bearer \(access_token)"
];
Alamofire.request(.POST, url, parameters: param, headers: headers)
.responseJSON { response in {
// take care of response here
}
But instead of the result, I get 400 bad request error. I also even try this:
let param = populateParamWithDictionary();
let url = "https://www.example.com";
let headers : Dictionary<String, String> = [
"Content-Type":"application/json",
"Authorization":"Bearer \(access_token)"
];
Alamofire.request(.POST, url, parameters: param, encoding: ParameterEncoding.JSON, headers: headers)
.responseJSON { response in {
// take care of response here
}
But the result is even worse. This is what I get when I print the response.
FAILURE: Error Domain=NSURLErrorDomain Code=-1017 "cannot parse
response" UserInfo={NSUnderlyingError=0x7fbb505788f0 {Error
Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)"
UserInfo={_kCFStreamErrorCodeKey=-1, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://lfapp.learnflux.net/v1/me,
NSErrorFailingURLKey=http://lfapp.learnflux.net/v1/me,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1, NSLocalizedDescription=cannot parse response}
But the request works if I use REST client, by setting the headers to have the authentication and Content-Type, and have the parameters to be written as plain Content, e.g. in plain API in the body content.
How can I fix this?
EDIT: The part with the access token is already clear. The access token works. I can call an API successfully if the API doesn't requires any parameters (maybe because on the server, the code doesn't bother to even check or validate the body at all because it doesn't need anything from there, hence no error raised). The problem is when I make a request which needs any parameters.
The error you have is probably because of encoding: ParameterEncoding.JSON in the request. Try to change it to encoding: .URLEncodedInURL. If this doesn't help you, do add your parameters to the question and if you´re make a request to get the token do the following:
if let access_token = json["access_token"]!{
// Make the request here when you know that you have your token
}

Resources