Open WiRight opened 1 day ago
Update
For now i use next solution
@Path
struct Chats {
init (client: APIClient) {
self.client = client.auth(enabled: true)
}
@GET("/")
func list() async throws -> [Chat] {
client.auth(.bearer(token: AuthStore().accessToken)) // <-- here
}
}
AuthStore
- is a ObservableObject wich stores accessToken
via @AppStorage
Is it clear?
My bad...
Find solution
@API
public struct ApiClient {
init(baseUrl: BaseURL) {
client = APIClient(baseURL: baseUrl.url)
.path("v1")
.bodyDecoder(ApiDecoder())
.bodyEncoder(.json)
.errorDecoder(.decodable(ApiResponse<String>.self))
.auth(.bearer(token: AuthStore().accessToken)) // <-- Paste auth here
.queryEncoder(.urlQuery(arrayEncodingStrategy: .commaSeparator))
// TODO: new error is here
.tokenRefresher { refreshToken, client, _ in
guard let refreshToken else {
throw ApiResponse<String>(
status: "error",
message: "No refresh token",
error: "No refresh token",
data: nil
)
}
let refreshInfo: AuthResponse = try await client("chats", "refresh")
.body(["refresh_token": refreshToken])
.put()
return (refreshInfo.token.accessToken, refreshInfo.token.refreshToken, nil)
}
}
}
But i have new trouble - with tokenRefresher
getting error
If comment - all be ok
Finally done
Creating custom SecureCacheService
was solution for me
Leave code here
ApiClient.swift
public struct MKeychainCacheService: SecureCacheService {
public static var `default` = MKeychainCacheService()
public func load(for key: SecureCacheServiceKey) throws -> String? {
UserDefaults.standard.string(forKey: key.value)
}
public func load(for key: SecureCacheServiceKey) async throws -> String? {
UserDefaults.standard.string(forKey: key.value)
}
public func save(_ value: String?, for key: SecureCacheServiceKey) async throws {
UserDefaults.standard.setValue(value, forKey: key.value)
}
public func clear() async throws {
UserDefaults.standard.setValue(nil, forKey: SecureCacheServiceKey.accessToken.value)
UserDefaults.standard.setValue(nil, forKey: SecureCacheServiceKey.refreshToken.value)
UserDefaults.standard.setValue(nil, forKey: SecureCacheServiceKey.expiryDate.value)
}
}
@API
public struct ApiClient {
init(baseUrl: BaseURL) {
client = APIClient(baseURL: baseUrl.url)
.path("v1")
.bodyDecoder(ApiDecoder())
.bodyEncoder(.json)
.errorDecoder(.decodable(ApiResponse<String>.self))
.queryEncoder(.urlQuery(arrayEncodingStrategy: .commaSeparator))
.tokenRefresher(
cacheService: MKeychainCacheService(),
refresh: { refreshToken, client, _ in
guard let refreshToken else {
throw ApiResponse<String>(
status: "error",
message: "No refresh token",
error: "No refresh token",
data: nil
)
}
let refreshInfo: AuthResponse = try await client("chats", "refresh")
.body(["refresh_token": refreshToken])
.put()
return (refreshInfo.token.accessToken, refreshInfo.token.refreshToken, nil)
}
)
}
}
// Other api @Path here...
May be this issue can be closed, but i'm not sure that this way is clear
Hello! Thx for your library!
I'm new in Swift
I've created
ApiClient
via macros and add two methods - login and refresh. How to passacessToken
fromlogin
request into other requests?