SwiftUI - Combine 和 Alamofire 解析错误响应
SwiftUI - Combine and Alamofire parse error Response
我的 api .post
方法有这个通用实现:
func post<T: Decodable>(endpoint: Endpoint, parameters: Parameters, responseType: T.Type) -> AnyPublisher<T, Error> {
sessionManager.request(self.baseUrl + endpoint.path, method: .post, parameters: parameters)
.publishDecodable(type: responseType)
.value()
.mapError(ServiceError.init(error: ))
.eraseToAnyPublisher()
}
它正在运行,我认为它在 SwiftUI/Combine 中应该是这样的。我的问题是当我得到其他状态代码然后是 2xx 时,我希望能够解析响应。我对如何做感到困惑 and this article。
在这些帮助下,我能够将我的代码更改为:
func post<T: Decodable>(endpoint: Endpoint, parameters: Parameters, responseType: T.Type, completionHandler: @escaping (Result<T, ErrorResponse>) -> Void) {
sessionManager.upload(multipartFormData: multipartFormData, to: self.baseUrl + endpoint.path, method: .post, headers: headers)
.validate(statusCode: 200..<300)
.responseTwoDecodable(of: responseType, completionHandler: completionHandler)
}
有关更多信息,请参阅我的 TwoDecodableResponseSerializer
(在这两个链接的帮助下创建):
final class TwoDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
lazy var decoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return decoder
}()
private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
private lazy var errorSerializer = DecodableResponseSerializer<ErrorResponse>(decoder: decoder)
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Result<T, ErrorResponse> {
guard let response = response else { return .failure(ErrorResponse()) }
do {
if response.statusCode < 200 || response.statusCode >= 300 {
let result = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
return .failure(result)
} else {
let result = try successSerializer.serialize(request: request, response: response, data: data, error: nil)
return .success(result)
}
} catch(let err) {
return .failure(ErrorResponse())
}
}
}
extension DataRequest {
@discardableResult func responseTwoDecodable<T: Decodable>(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated), of t: T.Type, completionHandler: @escaping (Result<T, ErrorResponse>) -> Void) -> Self {
return response(queue: .main, responseSerializer: TwoDecodableResponseSerializer<T>()) { response in
switch response.result {
case .success(let result):
completionHandler(result)
case .failure(let error):
completionHandler(.failure(ErrorResponse()))
}
}
}
}
和错误响应:
class ErrorResponse: Error, Decodable {
var error: Int = 0
enum CodingKeys: String, CodingKey {
case error = "error"
}
}
它正在运行。太好了,但我想要更多 reactive/Combine 代码。不关闭。可能吗?你会怎么做?
感谢您的帮助
如果您使用自己的 ResponseSerializer
,您可以使用 publishResponse(using:on:)
方法将其与 Combine 一起使用。
我的 api .post
方法有这个通用实现:
func post<T: Decodable>(endpoint: Endpoint, parameters: Parameters, responseType: T.Type) -> AnyPublisher<T, Error> {
sessionManager.request(self.baseUrl + endpoint.path, method: .post, parameters: parameters)
.publishDecodable(type: responseType)
.value()
.mapError(ServiceError.init(error: ))
.eraseToAnyPublisher()
}
它正在运行,我认为它在 SwiftUI/Combine 中应该是这样的。我的问题是当我得到其他状态代码然后是 2xx 时,我希望能够解析响应。我对如何做感到困惑
在这些帮助下,我能够将我的代码更改为:
func post<T: Decodable>(endpoint: Endpoint, parameters: Parameters, responseType: T.Type, completionHandler: @escaping (Result<T, ErrorResponse>) -> Void) {
sessionManager.upload(multipartFormData: multipartFormData, to: self.baseUrl + endpoint.path, method: .post, headers: headers)
.validate(statusCode: 200..<300)
.responseTwoDecodable(of: responseType, completionHandler: completionHandler)
}
有关更多信息,请参阅我的 TwoDecodableResponseSerializer
(在这两个链接的帮助下创建):
final class TwoDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
lazy var decoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return decoder
}()
private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
private lazy var errorSerializer = DecodableResponseSerializer<ErrorResponse>(decoder: decoder)
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Result<T, ErrorResponse> {
guard let response = response else { return .failure(ErrorResponse()) }
do {
if response.statusCode < 200 || response.statusCode >= 300 {
let result = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
return .failure(result)
} else {
let result = try successSerializer.serialize(request: request, response: response, data: data, error: nil)
return .success(result)
}
} catch(let err) {
return .failure(ErrorResponse())
}
}
}
extension DataRequest {
@discardableResult func responseTwoDecodable<T: Decodable>(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated), of t: T.Type, completionHandler: @escaping (Result<T, ErrorResponse>) -> Void) -> Self {
return response(queue: .main, responseSerializer: TwoDecodableResponseSerializer<T>()) { response in
switch response.result {
case .success(let result):
completionHandler(result)
case .failure(let error):
completionHandler(.failure(ErrorResponse()))
}
}
}
}
和错误响应:
class ErrorResponse: Error, Decodable {
var error: Int = 0
enum CodingKeys: String, CodingKey {
case error = "error"
}
}
它正在运行。太好了,但我想要更多 reactive/Combine 代码。不关闭。可能吗?你会怎么做?
感谢您的帮助
如果您使用自己的 ResponseSerializer
,您可以使用 publishResponse(using:on:)
方法将其与 Combine 一起使用。