I'm trying to handle Alamofire errors globally, similar to this: AFNetworking: Handle error globally and repeat request
One use case would be to detect a 400 status code error (unauthorized / expired API token) and present the login page. Is there a way to hook on something in the Alamofire core or should I create my own error handler and always call validate().response() manually each time?
Thanks
At the moment you will have to handle that logic in your own custom response implementation. We (the Alamofire TC) are currently working on ways that we can make this process easier, but it's very difficult to get right without complicating the rest of the APIs. We're still a ways off yet.
With that said, I built an OAuth 2.0 system that handles this process in a different non-open-source library. It is possible, it's just difficult to do. You will need to hook into the response closure for all requests that could 401. See my answer here for a full breakdown of how to do this.
Hopefully that helps shed some light. Cheers 🍻
Related
I'm handling the server trust authentication challenge in a custom way (comparing the public key from the server trust with a hashed local version) through the urlSessionDelegate, similarly to how it is done here:
How do I accept a self-signed SSL certificate using iOS 7's NSURLSession and its family of delegate methods for development purposes?
As described in the documentation, I need to cancel the challenge if I want to fail the server trust authentication myself. When doing this, my data task will complete with the NSURLErrorCancelled. I have some error handling classes which look at the resulting NSURLError returned by the datatask, and it would be a lot cleaner for me if I got NSURLErrorServerCertificateUntrusted instead.
Is there a way to achieve that? Or will those server errors only be forwarded when the authentication is handled automatically, without the delegate methods?
Would the normal handling of the certificate in question fail with that error?
If so, you could use NSURLSessionAuthChallengePerformDefaultHandling in that case.
If not, I think the only way would involve mucking around with the challenge sender, which is highly discouraged, though it might not be catastrophic if you call that and afterwards call the proper completion handler. There's a good chance you'd get two callbacks, though. I've never attempted this.
My advice would be to file a bug with Apple asking for a proper API to pass an NSError along with cancellation.
UPDATE: I a using SwiftEventBus https://github.com/cesarferreira/SwiftEventBus and this seems to work fine. I can simply define event listeners that wait on each step. Still interested in other approaches for multi-step login process.
I need to solve a multipart login process (stuck on how to wrap logic around serial GET/POST requests)
also on github as https://github.com/Alamofire/Alamofire/issues/1746
step 1 validate user/pw with basic authentication header
step 2 use returned token (from step 1) in new authentication header and
fetch from server a list
step 3 user selects from returned list (or does another request to
create new if thing not found on list) - note really important what
the list is because I am just interested in the serialization and
wrapping logic across steps
step 4 use guid from selected/created thing to generate auth token to
fetch yet another new general use auth token and refresh token
I can do each of these individually (set headers, set parms, validate and parse result, etc), BUT I do not understand how to create the logic flow around the requests. Do I have to nest all of the requests inside each other so that I step 2 happens inside step 1, step 3 happens inside step 2, etc. Or is there a simple example application somewhere that shows how execute multiple requests with logic around the requests - Not interested in simply queueing the requests as I have to run logic around the requests. Event Bus? Managed queue? Other? Looking for guidance and ideally a downloadable sample app that I can play with and learn from.
I originally built this without Alamofire and had the request timing/logic problem and thought Alamofire might make this easier but after switching to Alamofire I find myself stuck at the same point. Open to a suggestion without Alamofire in order to learn how to do this.
This is not build into Alamofire per se because it is callback based but you can use the callbacks and nest each call to Alamofire into the other like that:
Alamofire.request("url").responseJSON { _ in
Alamofire.request("anotherUrl").responseJSON { _ in
Alamofire.request("yetAnotherUrl").responseJSON { _ in
//all three have finished with either response or error
}
}
}
This leads to a pattern often seen with callbacks that is also sometimes referred to as Pyramid of doom.
As an alternative you can check out either Promises or I like to use a reactive library like RxSwift that will give your code more of a 'waterfall' look.
There is also a PromiseKit extension and a RxSwift extenstion for Alamofire.
There are a wealth of resources for checking for a valid Internet connection with Swift (Reachability) and also ways to check the statusCode of the httpResponse when making an API call, but what is the "right" way to check and handle these errors (Internet not reachable, server 404) when dealing with an API heavy iOS app?
For example, when the app starts in the initial view (or AppDelegate I suppose) one can check for both and redirect to a "ServerProblemsViewController" that displays a message (or show an alert, though those can be dismissed). But what happens is someone is in the middle of using your app and the Internet drops or the server becomes unreachable? How would you handle this?
I am wondering if devs typically check for Reachability before EVERY API call and check the return status of EVERY API call, or somehow encapsulate that logic into a helper function?
How do experienced iOS devs deal with this situation?
I check for reachability on every call and then examine the response status code by type casting the NSURLResponse to an NSHTTPURLResponse (which has a statusCode property). And yes, my requests use the same base class to encapsulate all of the functionality--only creating derived classes when needed. You can use the reachability example code from Apple which has been ported to Swift and can be typically found on Github through the community. Simply reading through this repo will probably answer a lot of your questions about changes in reachability. Notifications FTW!: https://github.com/ashleymills/Reachability.swift
I discovered today Servlet 3.0 asynchronous facility. I have read about it and think I understood the concept.
I was wondering: would that make any difference on "standard" controller's actions, or should it be saved for the use of web services, or extensive computational processes ?
In other words, is it a bad idea to use it on all one's controller's actions, without considering the computational time of the actions method beforehand?
If it is, could you explained to me why ?
Thank you in advance.
No, this would be a bad idea.
On a controller action, you get a request and you want to serve a response as soon as possible. You can use the asynchronous only for thing that can be delayed.
If a user is requesting a page on your website, you can't respond with empty page, then do a push back to update his page. I would use this feature only for AJAX requests and even not for all of them. You have to decide what makes sense to run be run asynchronously and what not.
You should read the Grails documentation for Asynchronous Request Handling
In general for controller actions that execute quickly there is little benefit in handling requests asynchronously. However, for long running controller actions it is extremely beneficial.
The reason being that with an asynchronous / non-blocking response, the one thread == one request == one response relationship is broken. The container can keep a client response open and active, and at the same time return the thread back to the container to deal with another request, improving scalability.
Hopefully this should be clear enough, but please ask if something is not clear.
I've just started to try out RestKit for an iOS app i'm building. I normally use ASIHttpRequest, but I want to test out RestKit mostly for its object mapping between JSON and CoreData. There are some great things about RestKit, but I've run into an issue that really makes it feel deficient, unless I'm doing something wrong or have missed something. I hope someone here can guide me on that.
I'm using RKObjectLoader to make async & sync calls to a REST API. My service is designed to send back proper HTTP status codes, along with some sort of description, a 401 being an example of when the API needs an authenticated user.
My problem is that RestKit stops acting normally if i get a 401 error back. The RKResponse object has a status code of 0, even though it has a payload in it. I'm pretty sure this comes down to NSURLConnection's poor handling of HTTP statuses, but I would expect RestKit to wrap around this somehow. Especially since the RKResponse class has quite a few wrapper functions to determine the status code of the response (isOK, isCreated, isForbidden, isUnauthorized, etc.).
In comparison, ASIHttpRequest doesn't use NSURLConnection, but instead uses the lower level CFNetwork code. ASIHttpRequest allows me to see exactly what came back over HTTP without sending out errors left & right.
Question is, am I doing something wrong, or is this the expected behavior out of RestKit? Has anyone successfully been able to make a calls to [RKResponse isAuthenticated]? Although its inconclusive to me, is there any difference between running in async and sync mode in this regard. I did read somewhere that NSURLConnection run in sync mode will act a bit differently, even though the underlying code is just calling the async operations. Does this have more to do with me using RKObjectLoader as opposed to just RKRequest? Perhaps the fact that the payload can't map to a model causes anger, but it seems that the code is breaking earlier within RKRequest.sendSynchronously, prior to when mapping actually takes place.
Bottom line is my code needs to be able to freely read HTTP status codes. Any guidance would be most appreciated.
Haider
The common way for RestKit 0.20.x is to subclass RKObjectRequestOperation.
I wrote a blog article about this problem which can be found here:
http://blog.higgsboson.tk/2013/09/03/global-request-management-with-restkit/
See http://groups.google.com/group/restkit/msg/839b84452f4b3e26
"... when authentication fails, the authentication challenge gets cancelled and that effectively voids the request."
UPDATE:
RestKit already includes a delegate method for this:
(void)request:(RKRequest *)request didFailAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
Triggers before
(void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
When HTTP Basic authentication fails, so we can use this instead.