swift中标准嵌套JSON的可解码包装器

问题描述

我正在使用一个遵循非常相似的响应结构的 API:

{
    "error": "string item","success": true,"result": {
        "users" : [
              {
                "id": "20001","firstname": "John","lastname" : "Smith","address": "123 king street","email": "john.smith@gmail.com","mobile": "0412345678"
              },{
                "id": "20002","firstname": "Jack","lastname": "Master","address": "123 rainbow road","email": "jack.master@gmail.com","mobile": "0412345678"
              }
        ]
    }
}

api 根据端点返回不同的结果。我想创建一个标准的可解码 json 响应结构。然后我只是为每个不同的结果类型创建一个新的可解码结构。

这样的事情是理想的:

struct JSONResponse<T: Decodable>: Decodable {
    var error: String
    var success: Bool
    var result: T
}

这是我想要做

struct User: Decodable {
    var id: String
    var firstName: String
    var lastName: String
    var email: String
    
    enum CodingKeys: String,CodingKey {
        case users
    }
    
    enum UserKeys: String,CodingKey {
        case id,firstName = "firstname",lastName = "lastname",email,mobile
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let nestedContainer = try container.nestedContainer(keyedBy: UserKeys.self,forKey: .users)

        id = try nestedContainer.decode(String.self,forKey: .id)
        firstName = try nestedContainer.decode(String.self,forKey: .firstName)
        lastName = try nestedContainer.decode(String.self,forKey: .lastName)
        email = try nestedContainer.decode(String.self,forKey: .email)
    }
    
}

然后以这样的方式解码许多不同的响应

let res = try! JSONDecoder().decode(JSONResponse<User>.self,from: responseData!)
    

解决方法

在这种特定情况下,您有多个 User 对象,因此您需要某种容器:

struct Users: Decodable {
   var users: [User]
}

User 也不需要这么复杂:

struct User: Decodable {
   var id: String
   var firstName: String
   var lastName: String
   var email: String
}

然后解码为:

let users = JSONDecoder().decode(JSONResponse<Users>.self,from: responseData)