I am using Open Cart API. The api has a very weird mechanism..
The API return header status code 200 even on unauthorized access, instead of 401.And returns the 401 error code in the body as attached in the image.

This way, my response success block is triggered instead of retrying the request. I have been using the Alamofire Adapter and Retrier for a long and this seems to be working find when the header status code is 401. But the API returns me 401 status code in the body which doesn't trigger the delegate method while validating the request.
func should(_ manager: SessionManager,
retry request: Request,
with error: Error,
completion: @escaping RequestRetryCompletion)
How should i handle this situation... Is there a way i can call the retrier delegate method manually?
I managed to solve it as below. But is there any better way to solve this?
extension DataRequest {
public func validateBodyStatusCode() -> Self {
return validate { request,response,data in
PrinterHelper.jsonPrinter(self.delegate.data!)
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any]{
if let statusCode = json["statusCode"] as? Int, statusCode == 401{
let reason:AFError.ResponseValidationFailureReason = .unacceptableStatusCode(code: 401)
return .failure(AFError.responseValidationFailed(reason: reason))
}else{
return .success
}
}else{
return .success
}
} catch let error {
print("Json serialization error \(error)")
let reason:AFError.ResponseValidationFailureReason = .unacceptableStatusCode(code: response.statusCode)
return .failure(AFError.responseValidationFailed(reason: reason))
}
}
}
}
And using the custom Validation as
let apiRequest = manager!.request(networkAddress, method: EndPoint.method, parameters: parameter, encoding: enCodingFormat, headers:authFlagHeader).validateBodyStatusCode().responseJSON { (response) in
let parsedResult = ResponseParser<EndPoint.ResponseType>.parseResponse(withResponse: response)
callback(parsedResult.0,parsedResult.1)
}
@anishparajuli555 You've hit a rather prickly use case for us. Right now validate() is only intended for simple validation scenarios. As you've seen, it doesn't really work that well for validating something in the response data. In fact, that's a highly inefficient use of it, since the response data may then be decoded twice. At the moment I would suggest any validation you need to perform on the response data be done in a custom response serializer and not validate. In the future we'll be reevaluating validate()s capabilities and how it fits into Alamofire.
Have the same issue. API always send 200 status code and in json response body code with real response status.
@kiokumicu i have added solution above..please have a look
@anishparajuli555 yeap, I use it, thx.
Maybe guys add native support )
I have same problem. Have anyone know Alamofire 5 solved this case?
Just as a heads up for everyone interested, @jshier and I have been batting this around a lot over the past few days. Once we push the retry redesign PR #2704 through, we're going to attempt to add retry support to the post response serialization process. Right now, the retry process runs after validation, and then the response serialization process kicks off and retry is no longer an option.
Instead, we're thinking we're going to run a retry pass after validation, then run the first response serializer, run a retry pass, then run the next response serialization, then retry, etc. until we get through all the response serializers. If any response serializer encounters an error (say a 401 buried inside the JSON), your retrier will be called which will allow you to trigger a retry.
Now there are some seriously complex things we have to modify to make that work, but we're pretty sure at this point that it will. Anyways, I wanted to give everyone a heads up that we really want to solve this properly in AF5 and we're giving it a lot of attention. @ios4vn to answer your question directly, we do not have support for this case yet in master, but we'll start working on it very soon.
@cnoon thanks guy
@jshier / @cnoon - is there any available fix for problems like these in AF5? I鈥檓 on beta 6 and was curious your guys recommendations for a situation similar to OP. I am getting 200鈥檚 but there is in fact an error in the body that will cause me to refresh some tokens and then retry. What is your recommended solution given we are using AF5? Thanks again.
@croossin Once you need to parse response bodies as errors and return the value, it's usually easier and more efficient to do so in the response serialization phase, rather than in validation. Especially now, after beta 5, where the ability to trigger retry from serialization errors were added. So, for parsing, you have a few options:
responseDecodable and, if there was a failure decoding, attempt to parse your error body. (Make sure to pass a custom DispatchQueue and call back to .main for this.)responseData and do both the intended type parsing and the failure parsing in the response handler. (Make sure to pass a custom DispatchQueue and call back to .main for this.)ResponseSerializer-conforming type and do the parsing there. Then, just create your own error type and handle the particular case you need in a RequestRetrier to trigger the retry.
Personally, I write my own ResponseSerializer for all of my projects, especially those that need custom response handling like this.
Most helpful comment
@croossin Once you need to parse response bodies as errors and return the value, it's usually easier and more efficient to do so in the response serialization phase, rather than in validation. Especially now, after beta 5, where the ability to trigger retry from serialization errors were added. So, for parsing, you have a few options:
responseDecodableand, if there was a failure decoding, attempt to parse your error body. (Make sure to pass a customDispatchQueueand call back to.mainfor this.)responseDataand do both the intended type parsing and the failure parsing in the response handler. (Make sure to pass a customDispatchQueueand call back to.mainfor this.)ResponseSerializer-conforming type and do the parsing there.Then, just create your own error type and handle the particular case you need in a
RequestRetrierto trigger the retry.Personally, I write my own
ResponseSerializerfor all of my projects, especially those that need custom response handling like this.