[英]How to validate this JSON in Swift4?
有一個API,將其響應包裝在具有status
值和data
值的關聯數組中,其中data
包含錯誤對象或期望值:
錯誤回應:
{
"status":"error",
"data":{
"errormessage":"Duplicate entry '101' for key 'PRIMARY'",
"errorcode":1062
}
}
成功回應:
{
"status":"success",
"data":{
"user": {
"id": 1,
}
}
}
我想驗證以下響應:
public class func validateResponse(_ data : Data) -> WebServicesError?
{
struct WTPResponse : Decodable
{
let status : String
let data : Data
}
do {
let response = try JSONDecoder().decode(WTPResponse.self, from: data) // FAILS HERE
if let wtpError = try? JSONDecoder().decode(WTPAPIError.self, from: response.data) {
return WebServicesError.wtpError(WTPAPIError(code: wtpError.code, message: wtpError.message))
}
}
catch let error {
return WebServicesError.init(error: error)
}
return nil
}
當嘗試對錯誤的響應對象進行解碼時,它總是失敗: Expected to decode Data but found a dictionary instead.
我當時以為我可以將data
對象解碼為Swift類型的Data
,但這實際上是[String: Any]
字典。
1)如何驗證從API收到的Data
?
2)有沒有一種方法可以僅將JSON響應的“ data
”部分提取為Data
類型,以便可以解碼User
對象而不必為其提供status
和data
屬性?
正如其他答案所述,您基本上無法使用JSONDecoder
做到這一點,因為您無法為"data"
鍵解碼Data
。 您需要將其解碼為Dictionary<String, Any>
東西。 我可以想到一種方法,但是這樣做很麻煩,即使那樣,您最終還是使用Dictionary
而不是Data
,所以您必須重新編碼它才能使Data
稍后傳遞給JSONDecoder
。
也許這意味着您必須下降到較低級別的JSONSerialization
並“手動”瀏覽字典。 但是,如果您在解碼時確切地知道要尋找哪種響應,那么我建議您使用Swift Decodable
系統,而不要繞過它。
在最高級別,您有一個響應,可以是失敗或成功,並且在每種情況下都攜帶不同的數據有效負載。 這聽起來像帶有關聯值的Swift enum
:
enum WTPResponse {
case failure(WTPFailure)
case success(WTPSuccess)
}
我們希望它可以直接從JSON解碼,但是我們必須手動編寫Decodable
一致性。 對於具有關聯值的enum
,編譯器無法自動執行。 在編寫Decodable
一致性之前,讓我們定義我們需要的所有其他類型。
響應的類型由字符串"error"
或字符串"success"
標識,聽起來像另一個Swift enum
。 我們可以使這個enum
成為String
的RawRepresentable
,然后Swift可以使它成為Decodable
:
enum WTPStatus: String, Decodable {
case error
case success
}
對於故障響應類型,數據有效負載具有兩個字段。 這聽起來像Swift的struct
,並且由於字段是String
和Int
,因此Swift可以為我們提供Decodable
功能:
struct WTPFailure: Decodable {
var errormessage: String
var errorcode: Int
}
對於成功響應類型,數據有效載荷是一個用戶,該用戶具有一個id: Int
字段。 這聽起來像是兩個Swift struct
,Swift可以為我們提供Decodable
功能:
struct WTPSuccess: Decodable {
var user: WTPUser
}
struct WTPUser: Decodable {
var id: Int
}
這涵蓋了示例JSON中出現的所有內容。 現在,我們可以WTPResponse
使WTPResponse
符合Decodable
,如下所示:
extension WTPResponse: Decodable {
enum CodingKeys: String, CodingKey {
case status
case data
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
switch try container.decode(WTPStatus.self, forKey: .status) {
case .error: self = .failure(try container.decode(WTPFailure.self, forKey: .data))
case .success: self = .success(try container.decode(WTPSuccess.self, forKey: .data))
}
}
}
這是一個測試:
let failureJsonString = """
{
"status":"error",
"data":{
"errormessage":"Duplicate entry '101' for key 'PRIMARY'",
"errorcode":1062
}
}
"""
let successJsonString = """
{
"status":"success",
"data":{
"user": {
"id": 1,
}
}
}
"""
let decoder = JSONDecoder()
do {
print(try decoder.decode(WTPResponse.self, from: failureJsonString.data(using: .utf8)!))
print(try decoder.decode(WTPResponse.self, from: successJsonString.data(using: .utf8)!))
} catch {
print(error)
}
這是輸出:
failure(test.WTPFailure(errormessage: "Duplicate entry \'101\' for key \'PRIMARY\'", errorcode: 1062))
success(test.WTPSuccess(user: test.WTPUser(id: 1)))
這是Swift4 Codable無法使用的情況。 您必須手動解析JSON並注意各種情況。 https://github.com/SwiftyJSON/SwiftyJSON
正如shayegh所說,我不確定您將如何使用新的Codable
功能來做到這一點。
您可以改用JSONSerialization
類。 這樣會將您的JSON數據轉換為包含其他字典的Dictionary。 然后,您可以自己通過代碼查詢字典。
那將很容易。
我使用quicktype的多源模式為每種響應類型生成單獨的Codable
模型:
這是代碼。 您可以先嘗試解碼Response
,如果失敗,則可以嘗試解碼BadResponse
。
// let response = try? JSONDecoder().decode(Response.self, from: jsonData)
// let badResponse = try? JSONDecoder().decode(BadResponse.self, from: jsonData)
import Foundation
struct Response: Codable {
let status: String
let data: ResponseData
}
struct ResponseData: Codable {
let user: User
}
struct BadResponse: Codable {
let status: String
let data: BadResponseData
}
struct BadResponseData: Codable {
let errormessage: String
let errorcode: Int
}
struct User: Codable {
let id: Int
}
我認為這比嘗試將其表示為單一類型稍微整潔。 我還建議不要選擇性地解碼JSON,而是解碼所有JSON,然后從這些類型中選擇所需的數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.