I've been using codegen generated code in my viewControllers in order to call our API's for a little while. Now, I need to implement some logic to refresh our token once I get a 401 error code.
If I modify AlamofireImplementations.swift's execute function and do "manager.retrier = MyRetrier()" after "let manager = createSessionManager()", I am able to catch a failed call, and retry it if needed.
However, I don't want to modify it there as it will get overwritten next time I run codegen.
If I subclass it, and override createSessionManager, what am I supposed to with it? I mean, none of the API classes generated by codegen will be using my subclass.
Please, how can I set a retrier for codegen's Alamofire?
Swagger-codegen 2.3.0
cc @jgavris @ehyche @Edubits @jaz-ah
@sadanro100 one question I have is should this happen in AlamofireImplementations or be something application specific that you do up in the controllers - i.e. handle errors up top and do a :
.catch { error -> Void in
HandleAndRetry401s(error)
since it's possible you don't always want to retry or what happens if you get an error again on the retry... maybe you'll have backoff policy if you happen to get multiple 401's in a row...
-the other temporary option is what I've done in AlamofireImplementations when I want to do something custom is just run the generator and always run a special script after that makes automatic fixes to the code w/ sed+awk to replace parts w/ my own customizations. not as ideal but a possibility so you don't have to worry about things getting overwritten.
@jaz-ah Thanks for the response.
From what I understand, Alamofire has the Adapter and the Retrier features built-in so that we can deal with failed requests.
AlamofireImplementations.swift's function createSessionManager is overridable so that the Manager can be configured (to setup an Adapter and a Retrier for example) as it reads "May be overridden by a subclass if you want to control the session configuration".
I have successfully implemented my Adapter and Retrier with queue control, so these are not my issue.
What I actually need to understand is, if I subclass AlamofireRequestBuilder (where createSessionManager is) and override createSessionManager to set my Adapter and Retrier, all of my generated class will be calling AlamofireImplementations's AlamofireRequestBuilder, not mine I suppose.
Get my point?
Solved:
You gotta subclass RequestBuilderFactory and AlamofireRequestBuilder
After that you set SwaggerClientAPI.requestBuilderFactory = YourCustomClass()
Example bellow:
import UIKit
import Alamofire
class DCCustomAlamofireRequestBuilderFactory: RequestBuilderFactory {
func getBuilder<T>() -> RequestBuilder<T>.Type {
return DCCustomAlamofireRequestBuilder<T>.self
}
}
class DCCustomAlamofireRequestBuilder
override func createSessionManager() -> SessionManager {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = buildHeaders()
let handler = DCAuthenticationManager()
let manager = Alamofire.SessionManager(configuration: configuration)
manager.adapter = handler
manager.retrier = handler
return manager
}
}
SwaggerClientAPI.requestBuilderFactory = DCCustomAlamofireRequestBuilderFactory()
If I try to use a custom requestBuilderFactory... my client crashes in.. I don't understand because I am only subclassing and not even doing anything with the manager yet:
AlamofireRequestBuilder.processRequest.:
Could not cast value of type 'Foundation._NSSwiftData' (0x1128e4438) to 'XXXSearch.SearchProfilesResponse' (0x11079f938)
import Foundation
import Alamofire
import XXXSearch
class XXXAlamofireRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
return XXXAlamofireRequestBuilder<T>.self
}
func getBuilder<T:Decodable>() -> RequestBuilder<T>.Type {
return XXXAlamofireDecodableRequestBuilder<T>.self
}
}
open class XXXAlamofireRequestBuilder<T>: AlamofireRequestBuilder<T> {
/**
May be overridden by a subclass if you want to control the session
configuration.
*/
open override func createSessionManager() -> Alamofire.SessionManager {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = buildHeaders()
return Alamofire.SessionManager(configuration: configuration)
}
}
open class XXXAlamofireDecodableRequestBuilder<T:Decodable>: XXXAlamofireRequestBuilder<T> {
}
in AppDelegate
XXXSearchAPI.requestBuilderFactory = XXXAlamofireRequestBuilderFactory()
@sadanro100 any ideas?
looks like ur mixing up decodable and codable request builders
import UIKit
import Alamofire
class MACustomAlamofireRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
return MACustomAlamofireRequestBuilder<T>.self
}
func getBuilder<T:Decodable>() -> RequestBuilder<T>.Type {
return MACustomAlamofireDecodableRequestBuilder<T>.self
}
}
class MACustomAlamofireRequestBuilder<T>: AlamofireRequestBuilder<T> {
open override func createSessionManager() -> Alamofire.SessionManager {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = buildHeaders()
let handler = MAAuthenticationManager()
let manager = Alamofire.SessionManager(configuration: configuration)
manager.adapter = handler
manager.retrier = handler
return manager
}
}
class MACustomAlamofireDecodableRequestBuilder<T:Decodable>: AlamofireDecodableRequestBuilder<T> {
override func createSessionManager() -> Alamofire.SessionManager {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = buildHeaders()
let handler = MAAuthenticationManager()
let manager = Alamofire.SessionManager(configuration: configuration)
manager.adapter = handler
manager.retrier = handler
return manager
}
}
Then put this somewhere:
SwaggerClientAPI.requestBuilderFactory = MACustomAlamofireRequestBuilderFactory()
let handler = MAAuthenticationManager()
we did't find AuthenticationManager() in swagger code gen.
shall we create new AuthenticationManager() , can you provide the code for AuthenticationManager().
Obviously MAAuthenticationManager is my authentication manager, you have to implement your own, thats where the retrier and adapter implementions go
this documentation gives examples on how to create Authentication Manager, Retrier, Adaptor etc..
https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md
Most helpful comment