我想处理来自API的错误消息以显示为警报。
例如,当用户尝试将游戏添加到愿望清单中但之前已经添加时,API会返回此错误消息以及417状态代码:
{
"hasError" : true,
"errorMessage" : [
"Game is already in your wish list."
]
}
我想从'case .failure'中获取此错误消息,以在应用程序中显示为Alert。通常,它像NSError一样进行转换,但我想像以下模型一样处理它:
struct ErrorMessage: Codable {
var errorMessage: [String]
var hasError: Bool
}
我有一个HTTPManager:
class HttpManager {
static let shared = HttpManager()
private init() { }
enum HttpError: Error {
case invalidResponse(Data?, URLResponse?)
}
public func get(_ url: URL, token: String?, completionBlock: @escaping (Result<Data, Error>) -> Void) {
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("iOS", forHTTPHeaderField: "User-Agent")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
completionBlock(.failure(error!))
return
}
guard
let responseData = data,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode else {
completionBlock(.failure(HttpError.invalidResponse(data, response)))
return
}
completionBlock(.success(responseData))
}
task.resume()
}
public func post(_ url: URL, parameters: [String:Any]?, completionBlock: @escaping (Result<Data, Error>) -> Void) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("iOS", forHTTPHeaderField: "User-Agent")
if parameters != nil{
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters!, options: .prettyPrinted) else {
return
}
request.httpBody = httpBody
}
//HTTP Headers
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
completionBlock(.failure(error!))
return
}
guard
let responseData = data,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode else {
completionBlock(.failure(HttpError.invalidResponse(data, response)))
return
}
completionBlock(.success(responseData))
}
task.resume()
}
}
我这样调用API:
func postWishList(game: Int, platform: Int, completion: @escaping (Result<BaseAddWishList, Error>) -> Void) {
let url = baseURL + postWishListURL
let params = ["gameId": game, "platform": platform] as [String : Any]
HttpManager.shared.post(URL(string: url)!, parameters: params) { result in
switch result {
case .failure(let error):
DispatchQueue.main.async { completion(.failure(error)) }
case .success(let data):
do {
let res = try JSONDecoder().decode(BaseAddWishList.self, from: data)
DispatchQueue.main.async { completion(.success(res)) }
} catch {
print("Unable to retrieve string representation")
DispatchQueue.main.async { completion(.failure(error)) }
}
}
}
}
还有我的ViewModel函数(我想在这里接收errorMessage以便在警报中显示)
func postWishList(game: Int, platform: Int){
ApiManager.shared.postWishList(game: game, platform: platform) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let result):
print(result)
case .failure(let err):
print(err)
// I need errorMessage string at here to show as an Alert.
}
}
}
答案 0 :(得分:1)
如果您的服务器针对此类错误返回417,则必须删除200..<300
状态代码检查。然后dataTask
方法可以提供更精细的状态码检查:
public func post(_ url: URL, parameters: [String: Any]?, completion: @escaping (Result<Data, Error>) -> Void) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = parameters.flatMap { try?JSONSerialization.data(withJSONObject: $0) }
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let responseData = data,
let httpResponse = response as? HTTPURLResponse
else {
completion(.failure(HttpError.invalidResponse(data, response)))
return
}
switch httpResponse.statusCode {
case 200..<300:
completion(.success(responseData))
case 417: // if there are others, add them to this list
completion(.failure(HttpError.apiError(httpResponse.statusCode, responseData)))
default:
completion(.failure(HttpError.invalidStatusCode(httpResponse.statusCode)))
}
}
task.resume()
}
哪里
enum HttpError: Error {
case invalidResponse(Data?, URLResponse?)
case invalidStatusCode(Int)
case apiError(Int, Data)
}
然后在发布愿望时,您可以捕获以下状态代码并解析响应:
func postWishList(game: Int, platform: Int, completion: @escaping (Result<BaseAddWishList, Error>) -> Void) {
let url = baseURL + postWishListURL
let params = ["gameId": game, "platform": platform] as [String : Any]
HttpManager.shared.post(URL(string: url)!, parameters: params) { result in
switch result {
case .failure(let postError):
let error: Error
switch postError {
case HttpManager.HttpError.apiError(417, let data):
do {
let res = try JSONDecoder().decode(ErrorMessage.self, from: data)
error = ApiError.wishFailure(res.errorMessage)
} catch let parseError {
error = parseError
}
default:
error = postError
}
DispatchQueue.main.async { completion(.failure(error)) }
case .success(let data):
do {
let res = try JSONDecoder().decode(BaseAddWishList.self, from: data)
DispatchQueue.main.async { completion(.success(res)) }
} catch {
print("Unable to retrieve string representation")
DispatchQueue.main.async { completion(.failure(error)) }
}
}
}
}
坦率地说,如果在整个API中都使用此ErrorMessage
模式,我可能会将错误的分析移到HttpManager
中,但是希望以上内容足以说明该模式。