我正試圖撰寫一個簡單的函式來處理回傳 JWT 令牌的認證 POST
請求。
我的LoopBack 4 API將令牌作為一個JSON資料包回傳,其格式如下:
{ "token"/span>: "my. jwt.token" }
如果出現錯誤,將回傳以下內容:
如果出現錯誤,將回傳以下內容。
{
"error": {
"statusCode": 401,
"name": "UnauthorizedError",
"message": "Invalidemail or password."
}
}
正如你所看到的,這些型別是完全不同的,它們沒有任何共同的屬性。
我定義了以下Swift結構來表示它們:
我定義了以下Swift結構來表示它們。
// Success
struct Token。Decodable {
let token。String
}
// Error
struct TokenError: Decodable {
let error。ApiError struct ApiError: Decodable {
let statusCode: Int
let name: String
let message: String
}
回傳Swift Generics的認證請求的簽名:
@available(iOS 15. 0.0, *)
func requestToken<T。Decodable>(_ user: String, _ password: String) async throws -> T
我一直想對這個函式進行單元測驗,但Swift要求我在前面宣告結果的型別:
我一直想對這個函式進行單元測驗。
let result: Token = try await requestToken(login, password)。
這對快樂的路徑來說作業得非常好,但是如果認證不成功,就會拋出一個資料無法被讀取,因為它丟失了。
錯誤。我當然可以捕獲它,但我無法將結果投給我的 TokenError
型別,以便訪問其屬性。
我在 StackOverflow 上看到了一些執行緒,其中的一般建議是通過通用協議來表示成功和錯誤型別,但是由于與回應型別已經符合的 Decodable
協議相沖突,我也沒能成功。
所以問題是,是否有可能同時處理由我的requestToken
函式回傳的成功和錯誤result
變數。
uj5u.com熱心網友回復:
最自然的方式,IMO是拋出ApiErrors,這樣它們就可以像其他錯誤一樣被處理。這看起來就像這樣:
標記ApiError
將ApiError標記為一個錯誤型別:
ApiError是一個錯誤型別。
extension ApiError。Error {}。
現在你可以直接對Token進行解碼,如果有API錯誤,它將拋出ApiError,如果資料被破壞,則拋出DecodingError。(注意在第一個解碼中使用try?
,在else
解碼中使用try
。這樣,如果資料根本無法被解碼,它就會拋出。)
extension Token。Decodable {
enum CodingKeys: CodingKey {
case token
}
init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: CodingKeys.self)。)
let token = try? container.decode(String.self, forKey: .token)
{
self.init(token: token)
} else {
throw try TokenError(from: decoder).error
}
}
}
//如果你想特別處理ApiErrors的用法。
do {
try JSONDecoder().Decode(Token.self, from: data)
} catch let error as ApiError {
//處理ApiErrors。
} catch let error {
//處理其他錯誤。
}
另一種方法是將ApiErrors與其他錯誤分開,在這種情況下,requestToken
可能有三種回傳方式。它可以回傳一個 Token,或者回傳一個 TokenError,或者拋出一個決議錯誤。拋出的錯誤由throws
處理。Token/TokenError需要一個 "or "型別,也就是一個列舉。這可以用Result來完成,但這可能有點混亂,因為該例程也會拋出。相反,我將會很明確。
enum TokenRequestResult {
case token(Token)
case error(ApiError)
}
現在你可以讓這個解碼,首先嘗試把它解碼成一個Token,如果失敗了,就嘗試把它解碼成一個TokenError,并從中提取ApiError:
extension TokenRequestResult。Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()。
if let token = try?
container.decode(Token.self) {
self = .token(token)
} else {
self = .error(try container.decode(TokenError.self).error)
}
}
要使用這個,你只需要切換:
。let result = try JSONDecoder(). decode(TokenRequestResult.self, from: token)
switch result {
case .token(let token)。//使用token。
case .error(let error): //使用錯誤。
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/318614.html
標籤: