是否可以解碼來自物件內部具有未知密鑰的服務器的錯誤回應?我將如何處理這樣的回應?
現在我像這樣在 URLSession 上做了一個擴展
extension URLSession {
func post<T: Decodable, U: Encodable>(
_ type: T.Type = T.self,
data: U,
from url: URL,
keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .convertFromSnakeCase
) async throws -> T {
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let body = try JSONEncoder().encode(data)
let token = UserDefaults.standard.string(forKey: "AccessToken")
if token != nil {
request.setValue("Bearer \(token!)", forHTTPHeaderField: "Authorization")
}
do {
let (data, response) = try await upload(for: request, from: body)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = keyDecodingStrategy
let decoded = try decoder.decode(T.self, from: data)
return decoded
} catch {
print(error)
throw error
}
}
}
這樣我可以向后端發出 POST 請求并取回解碼的物件所以當我嘗試登錄時,我可以這樣做:
func login(email: String, password: String) async {
let body = LoginRequest(email: email, password: password)
let url = URL(string: "https://api.junoreader.com/api/auth/login")!
do {
let response = try await URLSession.shared.post(DetailModel<UserModel>.self, data: body, from: url)
setUser(data: response.data)
} catch {
print("api error")
print(error)
}
}
回應的樣子
struct DetailModel<T: Codable>: Codable {
var data: T
}
struct UserModel: Codable, Identifiable, ObservableObject {
let id: Int
let firstName: String
let lastName: String
let username: String
let bio: String
var name: String {
return "\(firstName ?? "") \(lastName ?? "")"
}
}
但是,當登錄憑據錯誤時,服務器會使用 403 回應 JSON 物件,如下所示
{
"data": {
"errors": {
"login": [
"Email/password do not match."
]
}
}
}
資料和錯誤鍵始終存在,但根據我所做的請求和后端的驗證,“登錄”可能會有所不同。所以“錯誤”也可能有多個鍵。
解碼此類錯誤物件的最佳方法是什么?如何在“post”函式中處理這些錯誤?同樣,當錯誤發生而不是立即拋出錯誤時,swift仍在嘗試解碼資料。
uj5u.com熱心網友回復:
您可以為 API 錯誤定義一個物件:
struct ApiErrorPayload: Decodable {
let errors: [String: [String]]
}
然后Error,您可以定義一個列舉,以便您可以拋出此錯誤(以及一般 HTTP 錯誤):
enum ApiError: Error {
case serviceError(ApiErrorPayload)
case httpError(Data, HTTPURLResponse)
}
然后您可以定義您的post方法來檢查狀態代碼并解碼您的錯誤物件或您的ApiErrors:
extension URLSession {
func post<T: Decodable, U: Encodable>(
_ type: T.Type = T.self,
data: U,
from url: URL,
keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .convertFromSnakeCase
) async throws -> T {
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let body = try JSONEncoder().encode(data)
if let token = UserDefaults.standard.string(forKey: "AccessToken") {
request.setValue("Bearer " token, forHTTPHeaderField: "Authorization")
}
let (data, response) = try await upload(for: request, from: body)
guard let response = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = keyDecodingStrategy
switch response.statusCode {
case 200 ..< 300:
return try decoder.decode(T.self, from: data)
case 400 ..< 500:
let payload = try decoder.decode(ApiErrorPayload.self, from: data)
throw ApiError.serviceError(payload)
default:
throw ApiError.httpError(data, response)
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/416823.html
標籤:
