Вложение словаря JSON внутри ключа? - PullRequest
1 голос
/ 24 марта 2019

Мне нужно отправить запрос внутри ключа, ожидая, что он будет выглядеть следующим образом:

 {
  "user": {
    "email": String,
    "password": String
  }
}

Я пытаюсь сделать это путем создания UserSignupRequest, который имеет свойства электронной почты и пароля и соответствуетcodable:

struct UserSignupRequest: Codable {
    let email: String
    let password: String

    enum CodingKeys: String, CodingKey {
        case email
        case password
    }
}

Затем создание параметров для alamofire с помощью:

case .signup(let request):
        return ["user": request]
}

Моя логика заключалась в том, что это создаст пары значений дочернего ключа внутри родительского ключа пользователя, однако в моем приложении фатальные ошибкис ошибками при попытке:

urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])

Я уверен, что решение является чем-то простым, но я не могу заставить его работать!большое спасибо

1 Ответ

2 голосов
/ 24 марта 2019

JSONSerialization

JSONSerialization работает только с простыми типами, такими как массивы, словари, строки, числа и т. Д.

Если вы хотите использовать его, то вам не нужно Codable вместо этого вам нужна функция func toDict() -> [String: Any], которая преобразует ваш UserSignupRequest в словарь.
Тогда ваш переключатель будет выглядеть следующим образом:

case .signup(let request):
    return ["user": request.toDict()]
}

JSONEncoder

JSONSerialization isстарый API, и если вы планируете использовать Codable, вам нужно использовать:

urlRequest.httpBody = try JSONEncoder().encode(parameters)

Общий параметр 'T' не может быть выведен

Я предполагаю, что вы получаете такие параметры, как:

func parameters(for request: RequestType) -> [String: Any] {
    switch request {
    case .signup(let request):
        return ["user": request]
    }
}

Поэтому, когда вы передаете свои параметры в кодировщик, он не знает, какой тип кодировать.

Чтобы решить, мы можем вернуть не просто словарь, а конкретный протокол / тип aka:

protocol Request {
    func encode(by encoder: JSONEncoder) throws -> Data
}
extension Request where Self: Encodable {
    func encode(by encoder: JSONEncoder) throws -> Data {
        /// since it will be method on specific type, JSONEncoder will know what type is encoding
        return try encoder.encode(self) 
    }
}

struct UserSignupRequest: Codable, Request {
    struct RequestData: Codable {
        let email: String
        let password: String
    }
    let data: RequestData

    enum CodingKeys: String, CodingKey {
        case data = "user"
    }
}

func parameters(for request: RequestType) -> Request {
    switch request {
    case .signup(let requestData):
        return UserSignupRequest(data: requestData)
    }
}

Так что теперь вы можете сделать

urlRequest.httpBody = try parameters.encode(by: JSONEncoder())
...