Reputation: 9
I want a diffrerent responseDecodable on the httpStatusCode
server return
if statusCode == 200
resonseBody
{id: number}
if statusCode 400..<500
resonseBody
{
code: String
timestamp: String
message: String
}
so now my code is
AF.request(url, method: .post, headers: header).responseData { response in
switch response.result {
case .success(let data) :
guard let response = response.response else {return}
let json = try? JSONSerialization.jsonObject(with: data)
switch response.statusCode {
case 200:
if let json = json as? [String: Any] , let message = json["id"] as? Int{print(message)}
case (400..<500):
if let json = json as? [String: Any] , let message = json["message"] as? String{print(message)}
default:
return
}
case .failure(let err) :
print(err)
}
}
I try this code convert responseDecodable
struct a: Codable {var id: Int}
struct b: Codable{
var code: String
var timestamp: String
var message: String
}
AF.request(url, method: .post, headers: header).responseDecodable(of: a.self) { response in
guard let data = response.value else {return}
print(data)
}
.responseDecodable(of: b.self) { response in
guard let data = response.value else {return}
print(data)
}
but this way Regardless statusCode return both a and b
I want stautsCode == 200 return a or statusCode 400..<500 return b
What should I Do?
Upvotes: 0
Views: 936
Reputation: 437412
AFAIK, Alamofire does not have a “decode one object for success and another for failure” implementation. You'll have to do this yourself.
If you really want a one distinct object for 2xx responses and another for 4xx responses, there are a few approaches:
Use validate
to handle the 2xx responses, and manually decode 4xx responses in the error handler.
AF.request(url, method: .post, parameters: parameters, headers: header)
.validate(statusCode: 200 ..< 300) // only 2xx are auto-decoded for us; handle 4xx responses in `failure` handler
.responseDecodable(of: Foo.self) { response in
switch response.result {
case .failure(let error):
guard
let statusCode = response.response?.statusCode,
400 ..< 500 ~= statusCode,
let data = response.data,
let apiError = try? JSONDecoder().decode(ApiErrorResponse.self, from: data)
else {
print("other error:", error) // didn't parse `ApiErrorResponse` object, so obviously some other error
return
}
print("apiError:", apiError) // this is our parsed API error object
case .success(let foo):
print("success:", foo)
}
}
If you want, you could write your own ResponseSerializer
to parse 2xx and 4xx responses differently:
struct ApiErrorResponse: Decodable, Error {
let code: String
let timestamp: String
let message: String
}
final class ApiResponseSerializer<T: Decodable>: ResponseSerializer {
lazy var decoder = JSONDecoder()
private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
private lazy var errorSerializer = DecodableResponseSerializer<ApiErrorResponse>(decoder: decoder)
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
if let error = error { throw error }
guard let response = response else { throw URLError(.badServerResponse) }
switch response.statusCode {
case 400 ..< 500:
let apiErrorObject = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
throw apiErrorObject
default:
return try successSerializer.serialize(request: request, response: response, data: data, error: nil)
}
}
}
And then you can do:
AF.request(url, method: .post, parameters: parameters, headers: header)
.response(responseSerializer: ApiResponseSerializer<Foo>()) { response in
switch response.result {
case .failure(.responseSerializationFailed(reason: .customSerializationFailed(error: let apiErrorObject))):
print("api response error:", apiErrorObject)
case .failure(let error):
print("some other error:", error)
case .success(let foo):
print("success:", foo)
}
}
I find the nesting of the parsed error object to be a little tedious, but it does abstract the 2xx vs 4xx logic out of the response
/responseDecoder
completion handler.
In both of these, I'm considering all 2xx responses as success, not just 200. Some servers return 2xx codes other than just 200.
Upvotes: 0