I replied in #744, but I continue to experience difficulties trying to sort this out, so I've made a new thread.
I need to be able to pass a bearer token (for some of my calls) and refresh it when necessary. Currently, I have the following class to handle all of my API calls:
import Foundation
import Moya
enum ApiService {
case signIn(email: String, password: String)
case like(id: Int, type: String)
}
extension ApiService: TargetType, AccessTokenAuthorizable {
var authorizationType: AuthorizationType {
switch self {
case .signIn(_, _):
return .basic
case .like(_, _):
return .bearer
}
}
var baseURL: URL {
return URL(string: Constants.apiUrl)!
}
var path: String {
switch self {
case .signIn(_, _):
return "user/signin"
case .like(_, _):
return "message/like"
}
}
var method: Moya.Method {
switch self {
case .signIn, .like:
return .post
}
}
var task: Task {
switch self {
case let .signIn(email, password):
return .requestParameters(parameters: ["email": email, "password": password], encoding: JSONEncoding.default)
case let .like(id, type):
return .requestParameters(parameters: ["messageId": id, "type": type], encoding: JSONEncoding.default)
}
}
var sampleData: Data {
return Data()
}
var headers: [String: String]? {
return ["Content-type": "application/json"]
}
}
private extension String {
var urlEscaped: String {
return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
}
var utf8Encoded: Data {
return data(using: .utf8)!
}
}
As @pietrocaselani suggested, here, I have tried to make sense of how to implement this in accordance with my above code, but I've been stuck now for many days.
Here is what that class looks like right now:
import Foundation
import Moya
public final class ApiProvider {
private var token: String = ""
private func isTokenValid() -> Bool {
// check expiration date
return false
}
func createProvider() -> MoyaProvider<ApiService> {
let requestClosure = createRequestClosure()
return MoyaProvider<ApiService>(requestClosure: requestClosure)
}
func createRequestClosure() -> MoyaProvider<ApiService>.RequestClosure {
let requestClosure = { [unowned self] (endpoint: Endpoint, done: @escaping MoyaProvider.RequestResultClosure) in
guard let request = try? endpoint.urlRequest() else {
done(.failure(MoyaError.requestMapping(endpoint.url)))
return
}
if (self.isTokenValid()) {
done(.success(request))
return
}
// How do I make this request from this class?
provider.request(.refreshAuthToken()) { result in
switch result {
case .success(let response):
print("Success")
done(.success(request))
case .failure(let error):
print("Error")
done(.failure(error))
}
}
}
return requestClosure
}
}
However, I'm unsure of a few things:
provider.request is obviously wrong, and self.request does not work either.Hi @user6724161
I see that you are not using AccessTokenPlugin, I may have forgotten to add this on the other issue.
I made a small but fully functional project now. Please take a look at TVDBClient https://github.com/pietrocaselani/Moya-RefreshToken-Example
This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
This issue has been auto-closed because there hasn't been any activity for at least 21 days. However, we really appreciate your contribution, so thank you for that! 馃檹 Also, feel free to open a new issue if you still experience this problem 馃憤.
@pietrocaselani
I see that you are doing:
// If we are authenticating, skip all logic to get or refresh token, so we return the default request mapping
if target is Authentication.Type { return MoyaProvider<T>.defaultRequestMapping }
In the request closure, but I think you should also include using the default request mapping if the authorization type is .none. How would this be done?
@user6724161 +1 did you manage to do that?
@pietrocaselani how can to do what @user6724161 spoke?
@pietrocaselani
I see that you are doing:
// If we are authenticating, skip all logic to get or refresh token, so we return the default request mapping if target is Authentication.Type { return MoyaProvider<T>.defaultRequestMapping }In the request closure, but I think you should also include using the default request mapping if the authorization type is
.none. How would this be done?
I replied in #744, but I continue to experience difficulties trying to sort this out, so I've made a new thread.
I need to be able to pass a bearer token (for some of my calls) and refresh it when necessary. Currently, I have the following class to handle all of my API calls:
import Foundation import Moya enum ApiService { case signIn(email: String, password: String) case like(id: Int, type: String) } extension ApiService: TargetType, AccessTokenAuthorizable { var authorizationType: AuthorizationType { switch self { case .signIn(_, _): return .basic case .like(_, _): return .bearer } } var baseURL: URL { return URL(string: Constants.apiUrl)! } var path: String { switch self { case .signIn(_, _): return "user/signin" case .like(_, _): return "message/like" } } var method: Moya.Method { switch self { case .signIn, .like: return .post } } var task: Task { switch self { case let .signIn(email, password): return .requestParameters(parameters: ["email": email, "password": password], encoding: JSONEncoding.default) case let .like(id, type): return .requestParameters(parameters: ["messageId": id, "type": type], encoding: JSONEncoding.default) } } var sampleData: Data { return Data() } var headers: [String: String]? { return ["Content-type": "application/json"] } } private extension String { var urlEscaped: String { return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! } var utf8Encoded: Data { return data(using: .utf8)! } }As @pietrocaselani suggested, here, I have tried to make sense of how to implement this in accordance with my above code, but I've been stuck now for many days.
Here is what that class looks like right now:
import Foundation import Moya public final class ApiProvider { private var token: String = "" private func isTokenValid() -> Bool { // check expiration date return false } func createProvider() -> MoyaProvider<ApiService> { let requestClosure = createRequestClosure() return MoyaProvider<ApiService>(requestClosure: requestClosure) } func createRequestClosure() -> MoyaProvider<ApiService>.RequestClosure { let requestClosure = { [unowned self] (endpoint: Endpoint, done: @escaping MoyaProvider.RequestResultClosure) in guard let request = try? endpoint.urlRequest() else { done(.failure(MoyaError.requestMapping(endpoint.url))) return } if (self.isTokenValid()) { done(.success(request)) return } // How do I make this request from this class? provider.request(.refreshAuthToken()) { result in switch result { case .success(let response): print("Success") done(.success(request)) case .failure(let error): print("Error") done(.failure(error)) } } } return requestClosure } }However, I'm unsure of a few things:
- How do I make the request to refresh the auth token in the class?
provider.requestis obviously wrong, andself.requestdoes not work either.- How would I use this class in other classes (for example, controllers) to make my calls? What if I wanted to make a call that _doesn't_ require a bearer token?
@user6724161 Please let me know if you solved this and how. Thanks.
I replied in #744, but I continue to experience difficulties trying to sort this out, so I've made a new thread.
I need to be able to pass a bearer token (for some of my calls) and refresh it when necessary. Currently, I have the following class to handle all of my API calls:import Foundation import Moya enum ApiService { case signIn(email: String, password: String) case like(id: Int, type: String) } extension ApiService: TargetType, AccessTokenAuthorizable { var authorizationType: AuthorizationType { switch self { case .signIn(_, _): return .basic case .like(_, _): return .bearer } } var baseURL: URL { return URL(string: Constants.apiUrl)! } var path: String { switch self { case .signIn(_, _): return "user/signin" case .like(_, _): return "message/like" } } var method: Moya.Method { switch self { case .signIn, .like: return .post } } var task: Task { switch self { case let .signIn(email, password): return .requestParameters(parameters: ["email": email, "password": password], encoding: JSONEncoding.default) case let .like(id, type): return .requestParameters(parameters: ["messageId": id, "type": type], encoding: JSONEncoding.default) } } var sampleData: Data { return Data() } var headers: [String: String]? { return ["Content-type": "application/json"] } } private extension String { var urlEscaped: String { return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! } var utf8Encoded: Data { return data(using: .utf8)! } }As @pietrocaselani suggested, here, I have tried to make sense of how to implement this in accordance with my above code, but I've been stuck now for many days.
Here is what that class looks like right now:import Foundation import Moya public final class ApiProvider { private var token: String = "" private func isTokenValid() -> Bool { // check expiration date return false } func createProvider() -> MoyaProvider<ApiService> { let requestClosure = createRequestClosure() return MoyaProvider<ApiService>(requestClosure: requestClosure) } func createRequestClosure() -> MoyaProvider<ApiService>.RequestClosure { let requestClosure = { [unowned self] (endpoint: Endpoint, done: @escaping MoyaProvider.RequestResultClosure) in guard let request = try? endpoint.urlRequest() else { done(.failure(MoyaError.requestMapping(endpoint.url))) return } if (self.isTokenValid()) { done(.success(request)) return } // How do I make this request from this class? provider.request(.refreshAuthToken()) { result in switch result { case .success(let response): print("Success") done(.success(request)) case .failure(let error): print("Error") done(.failure(error)) } } } return requestClosure } }However, I'm unsure of a few things:
- How do I make the request to refresh the auth token in the class?
provider.requestis obviously wrong, andself.requestdoes not work either.- How would I use this class in other classes (for example, controllers) to make my calls? What if I wanted to make a call that _doesn't_ require a bearer token?
@user6724161 Please let me know if you solved this and how. Thanks.
How about provider.request(.refreshAuthToken()) to MoyaProvider<ApiService>().request(.refreshAuthToken()) ?
Most helpful comment
Hi @user6724161
I see that you are not using
AccessTokenPlugin, I may have forgotten to add this on the other issue.I made a small but fully functional project now. Please take a look at
TVDBClienthttps://github.com/pietrocaselani/Moya-RefreshToken-Example