我正在尝试映射以下
SignUpRequest
结构
struct SignUpRequest: Encodable {
struct Customer: Encodable {
let email: String?
let firstname: String?
let lastname: String?
let privacy: Bool
let privacy2: Bool
}
let customer: Customer
let password: String?
}
在这样的 JSON 中:
{
"customer": {
"email": "[email protected]",
"firstname": "Mario",
"lastname": "Rossi",
"custom_attributes":[
{
"attribute_code":"consensopubb",
"value":"3"
},
{
"attribute_code":"consensopubb2",
"value":"5"
}
]
},
"password": "Password1!"
}
我尝试为我的结构创建自定义编码。
struct SignUpRequest: Encodable {
let customer: Customer
let password: String?
struct Customer: Encodable {
let email: String?
let firstname: String?
let lastname: String?
let privacy: Bool
let privacy2: Bool
enum CodingKeys: String, CodingKey {
case email
case firstname
case lastname
case attributes = "custom_attributes"
}
enum AttributeCodingKeys: String, CodingKey {
case code = "attribute_code"
case value
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(email, forKey: .email)
try container.encode(firstname, forKey: .firstname)
try container.encode(lastname, forKey: .lastname)
// ...
}
}
}
我的问题是我不知道如何将
privacy1
和 privacy2
属性编码为 JSON custom_attributes
数组。
-- 编辑 --
privacy1
和 privacy2
属性是 Bool
因为映射了两个用户可以选中或不选中的复选框。不幸的是 API 需要一个 custom_attributes
数组。如果 consensopubb
是 "3"
,则 privacy1
具有值 true
。如果 consensopubb2
是 "5"
,则 privacy2
具有值 true
。
一个可能的解决方案:
struct SignUpRequest: Encodable {
let customer: Customer
let password: String?
}
extension SignUpRequest {
struct Customer: Encodable {
let email: String?
let firstname: String?
let lastname: String?
let privacy1: Bool
let privacy2: Bool
enum CustomerCodingKeys: String, CodingKey {
case email
case firstname
case lastname
case attributes = "custom_attributes"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CustomerCodingKeys.self)
var codes: [AttributeCode] = []
if privacy1 {
codes.append(AttributeCode(value: "3", code: "consensopubb"))
}
if privacy2 {
codes.append(AttributeCode(value: "5", code: "consensopubb2"))
}
try container.encode(codes, forKey: .attributes)
try container.encode(email, forKey: .email)
try container.encode(firstname, forKey: .firstname)
try container.encode(lastname, forKey: .lastname)
}
}
}
extension SignUpRequest.Customer {
struct AttributeCode: Encodable {
let value: String
let code: String
enum AttributeCodingKeys: String, CodingKey {
case code = "attribute_code"
case value
}
}
}
测试:
let requests: [SignUpRequest] = [SignUpRequest(customer: .init(email: "email1",
firstname: "f1",
lastname: "l1",
privacy1: true,
privacy2: true),
password: "p1"),
SignUpRequest(customer: .init(email: "email2",
firstname: "f2",
lastname: "l2",
privacy1: false,
privacy2: true),
password: "p2"),
SignUpRequest(customer: .init(email: "email3",
firstname: "f3",
lastname: "l3",
privacy1: true,
privacy2: false),
password: "p3"),
SignUpRequest(customer: .init(email: "email4",
firstname: "f4",
lastname: "l4",
privacy1: false,
privacy2: false),
password: "p4")]
requests.forEach { aRequest in
do {
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys] //For debug purposes
let data = try JSONEncoder().encode(aRequest)
let jsonString = String(data: data, encoding: .utf8)!
print(jsonString)
} catch {
print("Error: \(error)")
}
}
现在,我创建了一个自定义
AttributeCode
结构以使事情变得更容易。当然,您可以自定义所有 encode
并避免使用该结构(这很容易,因为它是 [String: String]
,但我觉得有时如果 encode(to:)
对于用户来说太困难了(以便以后调试、修改) ,或者 encode(to:)
乍一看不够清晰,最好有明确的额外结构,如果需要的话可以将其设为私有,并且只能由 SignUpRequest.Customer
看到。
我在
Customer
上进行了自定义编码,但事实上,如果只有那个需要特殊编码并且您不想修改 SignUpRequest
的编码(如果是),则可以通过对 Customer
进行其他修改来完成不是通过更高的SignUpRequest
完成的),但是有了这个你应该有完整的想法。