Today we are going to discuss “how to retry a request using Alamofire, an HTTP networking library written in Swift. In this tutorial, we will use Petfinder API on “https://www.petfinder.com/developers/” so you need to create an account on this website to get your personal “API Key” and “Secret” if you want to use this website API for your API calls. When you logged in, you have access to your “API Key” and “Secret” on the developer section of your account.
You can also find a comprehensive description of how to use this API on “https://www.petfinder.com/developers/v2/docs/”.
Could you tell me “Where the problem exactly lies!”?
Okay, here we go. In the real world of iOS development if you want to get a proper response from your backend provider through API call you need something that identifies you are allowed to have access to these data. Although different providers may implement different algorithms for identification, using an access token is one of the most popular methods among them. So far we have investigated that we need something like an access token to get an appropriate response from the server and this will grant your access to the provider server. However; there are situations where your token expires and guess what, you will no longer get your desired response from the server. In this case, you send your request with the expired token to the server then your request fails and finally you have no result to update your user interface. In such cases, a logical approach is to retry the request which failed due to an expired token error but do not forget to refresh the access token before retrying the request.
Let’s track this from the beginning!
With your personal “API Key” and “Secret” obtained from the Petfinder website, you can send a request to get a token. Please note that this token will place in the header of your future requests to get animal details. Personally, I always create a network manager class which will be responsible for network calls and will pass the raw data in a completion handler. For the authorization purpose, we have to send a post request with the achieved API key and secret key from the Petfinder website.
As you can see in the above code, with perceived parameters from the shared instance of the network manager we call the authorize function and pass in the parameters. Then in the completion handler, if we have received data from the server, we map our results with JSONSerialization class to a dictionary to get a token from the response and save this token for future usage in the UserDefaults.
In the presented snippet, you can see the Network manager class with its properties and methods. Concerning the single responsibility principle from SOLID principles, this class will only be responsible to get data from the server and pass its result to the receiver. If we send a post request with Alamofire to https://api.petfinder.com/v2/oauth2/token URL, we can get a token from the server. As you can see, if we get a result from the server we pass the data in the completion handler, and in case of any error, we pass that error in the completion closure.
In the above code, you can investigate UserDefaultsManager class which is then responsible for persisting data like apiKey, secretKey, and token. You do not need to know what this class does but the important issue that you have to keep in mind is that you need to save the perceived token to add it to the requests’ header fields.
If you have sent the required parameters correctly you will see something like below by printing perceived data from the server.
Up to this phase, there is no problem with the token, but after 3600 seconds, the problem will show up. What exactly will happen after 3600 seconds? After this period which is exposed in the above response under “expires_in” key, your token will be expired and you can no longer get proper response from the server, more precisely all your request fails because your token is no longer valid to communicate with the server. This is exactly where retrying a request comes in handy. If you send a request with an expired token, you will get something like below as a response from the server.
It is retry time!
If you have ever had a look at Alamofire's request, there is an optional argument inside the request function which is named “interceptor”.
The above snippet reveals that the interceptor type is “RequestInterceptor”.
RequestInterceptor itself is a composition of “RequestAdapter” and “RequestRetrier” protocols which provide adapt and retry functions respectively. Note that RequestInterceptor extension provides a default implementation for these two functions, therefore if you write a class that conforms to this protocol but do not override these functions properly, you can not expect your interceptor to work appropriately.
Again I usually prefer to make my network manager class conforms to the RequestInterceptor protocol and assign the interceptor argument of my Alamofire requests to self which is NetworkManager itself like below.
In the request function of my NetworkManager class, I set the interceptor argument to self. Also notice “ .validate() “ being called before “ .responseJSON “. If you want to retry your Alamofire requests you have to inform Alamofire that your request has been failed, and using the validate function is one way to do so. According to Alamofire documentation this function “Validates that the response has a status code in the default acceptable range of 200…299 and that the content type matches any specified in the Accept HTTP header field” . If you get a response with a status code out of this range and an interceptor is set properly, it will retry your request. For our interceptor to work we have to implement adapt and retry function.
The first function that we have to implement is adapt. Generally adapt will be called just before that your Alamofire request starts its communication with the server. In this function, first, we check that there is any available token in the UserDefaults then we add this token to the header field of our requests and finally pass the modified request through completion. As I said, at this moment your request has not been sent to the server yet and after this modification, it will start to communicate with the server.
The second function that we have to implement is the retry function. As you can see, in this function first we check that our retry count is less than the maximum limit which in this case is three. If it is greater than the maximum limit, we pass doNotRetry in completion else first we call another function which will refresh our token. In this function completion, we check that if our token has been refreshed successfully or not if it was successful we will retry our request with this newly generated token.
This is how refresh token works. It first read the saved API key and secret key from the UserDefaults and then it sends an authorization request to the server, like what we see before. Finally, if it receives a valid token from the server, saves it in UserDefaults and passes true in completion else pass false in completion which means that it failed to refresh the token.
Sum it up!
To sum up, if your token is expired, first in the adapt function you add the expired token to the request header fields cause you do not know it has been expired. At this point, you receive a response with a status code of 401, and when the validate function calls it intercepts that tour request has been failed and it calls the retry function. Finally, in the retry function where it refreshes the token through refreshToken method, once again your request will be sent to the server but this time the newly refreshed token will be added to your request and this time it will work properly.
Thank you for taking the time to read this article. You can also find the source code of the project on my GitLab at “https://gitlab.com/aalemi76/afretryrequest”. I hope you enjoyed this tutorial if so please leave a like. Do not forget to connect with me on LinkedIn. Also, if there is any question please do not hesitate to comment it.