OAuth2
OAuth2 copied to clipboard
Alamofire 5 request retrier
Greetings,
I have a request. With all of the updates with Swift 5 and Alamofire, I was wondering if we might get an updated example of the retrier for Alamofire 5.
Thanks!
Mark
in Alamofire 5 you can pass along the retrier / adapter as part of the request.
The other change in Alamofire 5 is that the global Session
is no longer mutable. So you must create a new Session
with the adapter & retrier as parameters if you want this to be accessible per session, instead of per request. You can no longer change this on the fly in Session
itself.
I refactored the example to work with v5 yesterday, hope this is of help to you
import Foundation
import OAuth2
import Alamofire
class OAuth2RetryHandler: RequestRetrier, RequestAdapter {
let loader: OAuth2DataLoader
init(oauth2: OAuth2) {
loader = OAuth2DataLoader(oauth2: oauth2)
}
public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if let response = request.task?.response as? HTTPURLResponse, 401 == response.statusCode, let req = request.request {
var dataRequest = OAuth2DataRequest(request: req, callback: { _ in })
dataRequest.context = completion
loader.enqueue(request: dataRequest)
loader.attemptToAuthorize() { authParams, error in
self.loader.dequeueAndApply() { req in
if let comp = req.context as? RequestRetryCompletion {
comp(nil != authParams, 0.0)
}
}
}
}
else {
completion(.doNotRetry) // not a 401, not our problem
}
}
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
guard nil != loader.oauth2.accessToken else {
completion(.success(urlRequest))
return
}
do {
let request = try urlRequest.signed(with: loader.oauth2)
return completion(.success(request))
} catch {
print("Unable to sign request: \(error)")
return completion(.failure(error))
}
}
}
RequestRetryCompletion has no place here since dataRequest.context type is (RetryResult) -> Void)
Change to
self.loader.dequeueAndApply() { req in if let comp = req.context as? (RetryResult) -> Void { comp(nil != authParams ? .retry : .doNotRetry) } }
Thanks, I'm a n00b at Swift, but I will have a shot at refactoring it the next time I look at my project :-)
moreover, Alamofire 5 invokes two retry checks. One for validate() and another for serializer https://github.com/Alamofire/Alamofire/issues/2562
which effectively invokes oauth2.afterAuthorizeOrFail
two times for every request that have both validate() and responseJSON (for example).
I have no idea how to fix that at the moment.