Add networking layer and wire up v9 login flow with unit tests.
Introduce APIClient/AuthAPI, complete login with multi-account selection, and polish the login card UI with shadow and keyboard dismiss. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
53
suixinkan/Core/Networking/APIRequest.swift
Normal file
53
suixinkan/Core/Networking/APIRequest.swift
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// APIRequest.swift
|
||||
// suixinkan
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// HTTP 方法实体,限制网络层支持的请求方法。
|
||||
enum HTTPMethod: String {
|
||||
case get = "GET"
|
||||
case post = "POST"
|
||||
case put = "PUT"
|
||||
case delete = "DELETE"
|
||||
}
|
||||
|
||||
/// 强类型 API 请求实体,描述一次请求的方法、路径、参数、Header 和响应类型。
|
||||
nonisolated struct APIRequest<Response: Decodable> {
|
||||
var method: HTTPMethod
|
||||
var path: String
|
||||
var queryItems: [URLQueryItem]
|
||||
var headers: [String: String]
|
||||
var body: AnyEncodable?
|
||||
|
||||
/// 创建一个 API 请求,并把可编码请求体擦除为统一的 AnyEncodable。
|
||||
init<Body: Encodable>(
|
||||
method: HTTPMethod,
|
||||
path: String,
|
||||
queryItems: [URLQueryItem] = [],
|
||||
headers: [String: String] = [:],
|
||||
body: Body? = Optional<EmptyPayload>.none
|
||||
) {
|
||||
self.method = method
|
||||
self.path = path
|
||||
self.queryItems = queryItems
|
||||
self.headers = headers
|
||||
self.body = body.map(AnyEncodable.init)
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodable 类型擦除包装器,用于在 APIRequest 中保存任意请求体。
|
||||
nonisolated struct AnyEncodable: Encodable, Sendable {
|
||||
private let encodeValue: @Sendable (Encoder) throws -> Void
|
||||
|
||||
init<Value: Encodable>(_ value: Value) {
|
||||
encodeValue = { encoder in
|
||||
try value.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
try encodeValue(encoder)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user