Swift 错误类型服务器对来自 rest 的错误输入的响应 API
Swift error type server response for wrong input from rest API
希望你一切都好。我有个问题。我有一个带有电子邮件和密码的简单登录页面,还有一个像这样的用户对象
// 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
}
}
return类型是上层的(UserModel)。如果用户输入 his/her credentials true 则没有问题。但如果 he/she 输入了错误的凭据,麻烦就开始了。我无法从服务器解析 return 值。总是给我错误那一行。
控制台输出为:
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)
}
}
我按照 that medium link 创建了我的路由器和网络服务。如果您能帮助我解决这个问题,我将感到非常高兴和感激。或者给我一些关于网络 api 和使用的建议。
[编辑来自服务器的错误响应]
我的请求和响应消息体框架也是这样的:
祝你有愉快的一天。和良好的编码。
要解码两个不同的 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 LogInError: Decodable {
希望你一切都好。我有个问题。我有一个带有电子邮件和密码的简单登录页面,还有一个像这样的用户对象
// 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
}
}
return类型是上层的(UserModel)。如果用户输入 his/her credentials true 则没有问题。但如果 he/she 输入了错误的凭据,麻烦就开始了。我无法从服务器解析 return 值。总是给我错误那一行。
控制台输出为:
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)
}
}
我按照 that medium link 创建了我的路由器和网络服务。如果您能帮助我解决这个问题,我将感到非常高兴和感激。或者给我一些关于网络 api 和使用的建议。
[编辑来自服务器的错误响应]
我的请求和响应消息体框架也是这样的:
祝你有愉快的一天。和良好的编码。
要解码两个不同的 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 LogInError: Decodable {