又一个轮子。重新发明。
一个现代、轻量级(实际上只有两个方法)的 Swift 网络层,使用 async-await。
401
错误时,使用现有的 refreshToken
自动重试。Codable
类型的编码/解码以及 204
空响应。400...599
都可以解码自定义的 RichErrorBody
以处理失败情况。{
"error": "Your Server Error Message",
"domainCode": Your custom domain error code(Int)
}
您可以使用 Swift Package Manager 安装 Wheel,方法是将以下行添加到您的 Package.swift
文件中
dependencies: [
.package(url: "https://github.com/swiftDevelopmentPackages/wheel.git", from: "1.0.0")
]
然后,将 wheel 添加到您的目标依赖项中
targets: [
.target(name: "YourTarget", dependencies: ["wheel"]),
]
或者,只需使用 XCode 的包依赖项选项卡添加即可。
使用 Wheel 非常简单,因为它具有内置接口。
public protocol HTTPServing {
func request<T: Decodable>(authenticated: Bool, requestConfig: ConfigRequestConvertible) async throws -> T
func request(authenticated: Bool, requestConfig: ConfigRequestConvertible) async throws
}
实际上只有两种方法可以执行请求 🚀
首先,您需要创建 HTTPService
的实例。您可以通过将所需的依赖项传递给其初始化器来完成此操作
let tokenRefresher = YourTokenRefresher() // Your implementation of TokenRefreshing
let tokenStorage = YourTokenStorage() // Your implementation of TokenStoring
let commonHeaders = ["Custom-Header": "CustomValue"] // Your domain specific custom headers you want to append to every request. Content-Type, Authorization etc. is added automatically
let httpService = HTTPService(tokenRefresher: tokenRefresher,
tokenStorage: tokenStorage,
commonHeaders: commonHeaders)
ConfigRequestConvertible
协议用于配置 HTTP 请求。您需要为您要发出的每种类型的请求创建一个符合此协议的类型。
这是一个 ConfigRequestConvertible
的示例,用于获取用户的 GET 请求
enum YourRequestConfig: ConfigRequestConvertible {
case useCaseOne
case useCaseTwo
var baseURL: URL {
URL(string: yourAPIBaseURL)!
}
var path: String {
switch self {
case .useCaseOne:
return "useCaseOnePath"
case .useCaseTwo:
return "useCaseTwoPath"
}
}
var method: HTTPMethod {
switch self {
case .useCaseOne:
return .GET
case .useCaseTwo:
return .POST
}
}
var parameters: [String: Any] {
return [:] // your urlParams or request body
}
var headers: [String : String]? {
return [:] // your endpoint specific headers
}
}
struct User: Decodable {
let id: Int
let name: String
// other properties...
}
do {
let user: User = try await httpService.request(authenticated: true, requestConfig: YourRequestConfig().useCaseOne)
print("Received user: \(user)")
} catch {
print("Failed to fetch user: \(error)")
}
在此示例中,User 是一个表示用户的 Decodable
结构体。YourRequestConfig
是一个 ConfigRequestConvertible
,它配置一个 GET
请求以获取用户。authenticated: true
假设您的 TokenRefreshing
可注入对象持有一个有效的 accessToken
& refreshToken
对,如果不是,则尝试刷新或使其失效。
do {
try await httpService.request(authenticated: false, requestConfig: YourRequestConfig().useCasetTwo)
print("User updated successfully.")
} catch {
print("Failed to update user: \(error)")
}
在此示例中,YourRequestConfig
是一个 ConfigRequestConvertible
,它配置一个 PUT
请求以更新用户。由于响应不需要解码为模型,因此请求方法的返回类型为 Void
。authenticated: Bool
的相同规则适用于上一个示例。