Пользовательская кодировка структуры

Я пытаюсь отобразить следующую структуру 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.

Кастом encode(to:) надо делать только в Customer, нет? Быстрый способ — создать struct CustomAttributes: Encodable и создать его из значений privacy1 и privacy2. Я думаю, вы читали эти значения, чтобы создать их?

Larme 29.04.2024 10:18

Как можно преобразовать Bool в значения массива custom_attributes? Почему вы используете Bool для этих двух свойств? Или это жестко закодированные значения, а Bool означает только то, следует ли их включать или нет?

Joakim Danielson 29.04.2024 10:19

@JoakimDanielson Я отредактировал свой вопрос, чтобы ответить на твой вопрос.

Giorgio 29.04.2024 10:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Возможное решение:

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), но с этим у вас должна быть вся идея.

Обновлено: если вам действительно не нужна структура AttributedCode, вы можете написать:

var codes: [[String: String]] = []
if privacy1 {
    codes.append(["value": "3", "attribute_code": "consensopubb"])
}
if privacy2 {
    codes.append(["value": "5", "attribute_code": "consensopubb2"])
}
try container.encode(codes, forKey: .attributes)

Если бы это была [String: Any], это было бы сложнее, и я бы все равно предложил использовать структуру AttributedCode, поскольку ее легче читать на первый взгляд, но оба решения работают и действительны.

Спасибо Ларме. Но просто ради интереса, по вашему мнению, есть ли способ достичь моей цели без использования структуры поддержки AttributeCode ?

Giorgio 29.04.2024 10:41

@Giorgio Вы можете изменить переменную массива на массив словарей, а затем использовать жестко запрограммированные значения в append. var attributes = [[String: String]]()а затем внутри предложения ifattributes.append(["attribute_code":"consensopubb", "value":"3"])

Joakim Danielson 29.04.2024 10:46

В предпоследнем абзаце я заявил, что это возможно, тем более, что это «легкий» [String: String] (это был бы [String: Any], который был бы более сложным.

Larme 29.04.2024 10:59

Другие вопросы по теме