Свифт типа ответа сервера для неправильного ввода из остальных API - PullRequest
1 голос
/ 10 февраля 2020

Надеюсь, у вас все хорошо. У меня вопрос. У меня есть простая страница входа с адресом электронной почты и паролем, а также у меня есть такой пользовательский объект

// MARK: - UserModel
struct UserModel: Codable {
    let error: Bool
    let desc: String
    let user: User
    let token: String
}

// MARK: - User
struct User: Codable {
    let id: Int
    let email, firstName, lastName, lang: String
    let status: Int
    let referer, star: String?
    let phone: String?
    let ip: String?
    let birth, idNumber: String?
    let regionID: String?
    let createdAt, updatedAt: String

    enum CodingKeys: String, CodingKey {
        case id, email
        case firstName = "first_name"
        case lastName = "last_name"
        case lang, status, referer, star, phone, ip, birth
        case idNumber = "id_number"
        case regionID = "region_id"
        case createdAt, updatedAt
    }
}

, тип возвращаемого значения - верхний (UserModel). Если пользователь ввел свои учетные данные true, проблем нет. Но неприятности начинаются, если он / она ввел неправильные учетные данные. Я не могу разобрать возвращаемое значение с сервера. Всегда выдавайте ошибку в этой строке.

Error Image

И вывод консоли:

Rentover[2343:150674] Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Bool, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "error", intValue: nil)], debugDescription: "Expected to decode Bool but found a dictionary instead.", underlyingError: nil)): file

Вот моя функция запроса входа в систему. Я использовал codable для простоты.

class func requestLogIn(router: Router, completion: @escaping (Result<UserModel, Error>) -> ()) {

    guard let url = setUrlComponents(router: router).url else { return }
    var urlRequest = URLRequest(url: url)
    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.httpMethod = router.method

    if router.method == "POST"{
        let model = LoginModel(email: router.parameters[0], password: router.parameters[1])
        urlRequest.httpBody = try? JSONEncoder().encode(model)
    }

    let dataTask = URLSession.shared.dataTask(with: urlRequest) { data, response, error in

        guard error == nil else {
            print(error?.localizedDescription)
            return
        }
        guard response != nil else {
            print("no response")
            return
        }
        guard let data = data else {
            print("no data")
            return
        }

        let responseObject = try! JSONDecoder().decode(UserModel.self, from: data)
        print(responseObject.user)
        DispatchQueue.main.async {
            completion(.success(responseObject))
        }


    }
    dataTask.resume()
}

И вот моя структура ошибок.

struct LogInError: Codable, Error{
    let error: Bool
    let desc: String
    let fields: [String] ----> 'Edit here old: let fileds: [String' 
}

И в последний раз моя функция реального вызова выглядит так:

    NetworkService.requestLogIn(router: Router.login(email: nameTextField.text!, passowrd: passwordTextField.text!)) { (result) in
        switch result {
        case .success(let userModel):
            print("RESULT SUCCESS")
            print("Hello \(userModel.user.firstName)")

            let selectedVC = UIUtils.checkUserStatus(status: userModel.user.status)
            self.navigationController?.modalPresentationStyle = .fullScreen
            self.navigationController?.pushViewController(selectedVC, animated: true)
        case .failure(let error):
            print("RESULT FAILED")
            print(error)
        }
    }

I перешел по этой средней ссылке для создания моего маршрутизатора и сетевого сервиса. Я очень рад и благодарен, если вы поможете мне с этим вопросом. Или дайте мне несколько советов о сетевых API и использовании.

[Редактировать для ответа об ошибке от сервера] Мой кадр сообщения запроса и ответа также выглядит так: Request Body and response message

Хорошего дня. И хорошей кодировки.

1 Ответ

0 голосов
/ 10 февраля 2020

Для декодирования двух разных строк JSON удобным решением является перечисление со связанными типами, поскольку оно может очень наглядно представлять регистры success и failure.

Сначала он декодирует общие error ключ и затем он декодирует UserModel или LogInError

enum Response : Decodable {
    case success(UserModel), failure(LogInError)

    private enum CodingKeys : String, CodingKey { case error }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let hasError = try container.decode(Bool.self, forKey: .error)
        if hasError {
            let errorContainer = try decoder.singleValueContainer()
            let errorData = try errorContainer.decode(LogInError.self)
            self = .failure(errorData)
        } else {
            let successContainer = try decoder.singleValueContainer()
            let successData = try successContainer.decode(UserModel.self)
            self = .success(successData)
        }
    }
}

Используйте его

class func requestLogIn(router: Router, completion: @escaping (Result<Response, Error>) -> ()) {

    ...

    do {
        let responseObject = try JSONDecoder().decode(Response.self, from: data)
        print(responseObject)
        DispatchQueue.main.async {
            completion(.success(responseObject))
        }
    } catch {
        DispatchQueue.main.async {
            completion(.failure(error))
        }
    }

и

NetworkService.requestLogIn(router: Router.login(email: nameTextField.text!, passowrd: passwordTextField.text!)) { (response) in
    switch response {
    case .success(let result):
        switch result {
            case .success(let userModel): 
                print("RESULT SUCCESS")
                print("Hello \(userModel.user.firstName)")

                let selectedVC = UIUtils.checkUserStatus(status: userModel.user.status)
                self.navigationController?.modalPresentationStyle = .fullScreen
                self.navigationController?.pushViewController(selectedVC, animated: true)
            case .failure(let errorData): 
                print(errorData)
        }

    case .failure(let error):
        print("RESULT FAILED")
        print(error)
    }
}

Объявите LoginError как стандартный Декодируемый struct

struct LogInError: Decodable {
...