debugPrint(response)
without validate()
:
[Request]: <NSMutableURLRequest: 0x10040ddd0> { URL: https://platform.devtest.ringcentral.com/restapi/oauth/token }
[Response]: <NSHTTPURLResponse: 0x10025f980> { URL: https://platform.devtest.ringcentral.com/restapi/oauth/token } { status code: 400, headers {
Connection = "keep-alive";
"Content-Language" = en;
"Content-Length" = 83;
"Content-Type" = "application/json;charset=UTF-8";
Date = "Fri, 26 Aug 2016 15:03:27 GMT";
RCRequestId = "3e87d7de-6b9e-11e6-a8f4-005056bb594d";
RoutingKey = SJC11P01PAS01;
Server = "nginx/1.8.0";
"Www-Authenticate" = "Basic realm=\"RingCentral REST API\"";
"X-LoadMetric" = 4;
} }
[Data]: 83 bytes
[Result]: SUCCESS: {
"error" : "invalid_request",
"error_description" : "Unsupported grant type"
}
[Timeline]: Timeline: { "Request Start Time": 493916605.929, "Initial Response Time": 493916607.145, "Request Completed Time": 493916607.146, "Serialization Completed Time": 493916607.146, "Latency": 1.217 secs, "Request Duration": 1.217 secs, "Serialization Duration": 0.000 secs, "Total Duration": 1.217 secs }
debugPrint(response)
with validate()
:
[Request]: <NSMutableURLRequest: 0x10040a5b0> { URL: https://platform.devtest.ringcentral.com/restapi/oauth/token }
[Response]: <NSHTTPURLResponse: 0x100365bd0> { URL: https://platform.devtest.ringcentral.com/restapi/oauth/token } { status code: 400, headers {
Connection = "keep-alive";
"Content-Language" = en;
"Content-Length" = 83;
"Content-Type" = "application/json;charset=UTF-8";
Date = "Fri, 26 Aug 2016 15:05:49 GMT";
RCRequestId = "9328183a-6b9e-11e6-b36a-005056bb26b9";
RoutingKey = SJC11P01PAS01;
Server = "nginx/1.8.0";
"Www-Authenticate" = "Basic realm=\"RingCentral REST API\"";
"X-LoadMetric" = 4;
} }
[Data]: 83 bytes
[Result]: FAILURE: Error Domain=com.alamofire.error Code=-6003 "Response status code was unacceptable: 400" UserInfo={StatusCode=400, NSLocalizedFailureReason=Response status code was unacceptable: 400}
[Timeline]: Timeline: { "Request Start Time": 493916746.708, "Initial Response Time": 493916749.121, "Request Completed Time": 493916749.121, "Serialization Completed Time": 493916749.122, "Latency": 2.413 secs, "Request Duration": 2.413 secs, "Serialization Duration": 0.001 secs, "Total Duration": 2.414 secs }
So where has the following data gone:
{
"error" : "invalid_request",
"error_description" : "Unsupported grant type"
}
The data is very useful message from server. But validate()
"eats" it.
I'm getting the same issue...
If you guys are referring to swift3 in Xcode8b6, then I can confirm that I am seeing this issue too :)
@jkoepcke I am referring to Swift 2.2 in XCode 7.3.1 It seems this issue has nothing to do with Swift version.
Agreed I'm also seeing it on XCode 7.3.1 and Swift 2.2. I think it's happening because it overrides the NSError with this new object that contains the domain, code and UserInfo. Instead it should probably leave the original object intact. See this line: https://github.com/Alamofire/Alamofire/blob/1fc8fb2bedb6045741f39d6c82e9cba6fdf36050/Source/Validation.swift#L86
Did someone found a workaround for this?
Why not use the response passed into the callback method? I don't think it deletes the content in the response just signals their is an error and you can do some extra processing to read the error message in the response' content.
'''
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
print("Validation Successful")
case .Failure(let error):
print(error)
print(response) //do extra stuff here.
}
}
'''
@jonathanpdiaz I gave up validate()
and do the validate myself by checking status code.
@tobiasoleary I print the response
in the body of this issue. And you can see that the useful message in response is gone. And that's why we have this issue here.
I also gave up on using validate() for now and am checking the status code manually.
On Aug 30, 2016, at 7:31 PM, Tyler Long [email protected] wrote:
@jonathanpdiaz I gave up validate() and do the validate myself by check status code.
@tobiasoleary I print the response in the body of this issue. And you can see that the useful message in the response is gone. And that's why we have this issue here.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
@gchaturvedi Are you using Alamofire 3.0? Because I having the full response even when their was an error was one of the major selling points for migrating to 3.0.
Second Bullet Point under Benefits of Upgrading
If you're using 2.0 here's an example of code I use to grab a custom error message from JSON.
class func completeAssignment(completeAssignmentURLPath completeAssignmentURLPath: String, musicNotation: String, completionHandler: (Result<JSONDict?>) -> Void) {
let timeOfRequest = NSDate()
Alamofire.request(SRFRouter.CompleteAssignment(completeAssignmentURLPath:completeAssignmentURLPath, musicNotation: musicNotation))
.validate()
.responseString {
(request, response, result) in
let deltaTime = -timeOfRequest.timeIntervalSinceNow
Analytics.trackTimedEvent(category: "API", timeInterval:deltaTime, name: "Complete Assignment", label: request?.URL?.absoluteString ?? "Unknown URL Path")
if let error = result.error as? NSError {
trackAPIErrorEvent(error, name: "Complete Assignment")
}
if (API.DEBUG_printErrorResponses && result.error != nil)
|| API.DEBUG_printAllResponses
|| API.DEBUG_printCompleteAssignmentResponse
{
APIDebug.printResponseString(request, response, result.value, result.error as? NSError, printCookies: API.DEBUG_printCookies)
}
}
.responseJSON {
(request, response, result) in
switch result {
case let .Success(value):
if let JSONDict = value as? JSONDict {
completionHandler(Result.Success(Box(JSONDict)))
} else {
completionHandler(Result.Success(Box([:])))
}
case let .Failure(data, error):
printError("API - Complete Assignment: \((error as NSError).description)")
// Treat No Value error as successful. Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
let acceptableStatusCodes = 200..<300
if let response = response, let data = data where acceptableStatusCodes.contains(response.statusCode) && data.isEqualToData(NSData()) {
completionHandler(Result.Success(Box([:])))
} else {
let appError = APIErrorFactory.errorWithResponse(response, responseJSON:result.value as? JSONDict, error: error as NSError)
completionHandler(Result.Failure(appError))
}
}
}
}
@tobiasoleary Thanks, I'm doing something similar with the chaining since I'm using .responseObject with ObjectMapper. I just think it's unfortunate to have to do .validate().responseString.responseJSON. Ideally, you should just have to use .responseJSON and if it's not a 2xx response, it'll trigger .Failure. In addition, it's very strange to have a non-2xx response actually bubble up in .Success. I will try to upgrade to 3.0 if it solves the issue, we're on Swift 2.2 so I'll have to see if it's even possible for me.
I just checked, I'm using pod 'Alamofire', '~> 3.4.1'. Still see this issue. @tobiasoleary
@tobiasoleary
Because I having the full response even when their was an error was one of the major selling points for migrating to 3.0.
Do you mean something like this [Result]: FAILURE: Error Domain=com.alamofire.error Code=-6003 "Response status code was unacceptable: 400" UserInfo={StatusCode=400, NSLocalizedFailureReason=Response status code was unacceptable: 400}
? But this is not the original message from server side.
Same problem here. I have to use my own validation method.
@tylerlong Does result.value not contain the error message from the server?
@tobiasoleary No, it doesn't. And that's why this issue was created in the first place.
It does contain some quite useless message like Response status code was unacceptable: 400
which is not the message from the server at all.
So to all of you convinced "the data is gone"...it's not.
The data is ALWAYS passed back to you in EVERY response serialization closure as part of the Response
object in AF 3. Take a look at the Response
struct:
/// Used to store all response data returned from a completed `Request`.
public struct Response<Value, Error: ErrorType> {
/// The URL request sent to the server.
public let request: NSURLRequest?
/// The server's response to the URL request.
public let response: NSHTTPURLResponse?
/// The data returned by the server.
public let data: NSData?
/// The result of response serialization.
public let result: Result<Value, Error>
/// The timeline of the complete lifecycle of the `Request`.
public let timeline: Timeline
}
Is the data
property not clear? Did anyone think to check it? Notice the [Data]: 83 bytes
that keep getting printed out when you use debugPrint
@tylerlong and @gchaturvedi? Come on guys, help yourselves out a bit here...
To your last point @tylerlong:
It does contain some quite useless message like Response status code was unacceptable: 400 which is not the message from the server at all.
How is that "useless"? The error tells you "exactly" what went wrong with the request. You told Alamofire to validate the request, it did and told you why it failed.
If you don't run validation on the response, you're saying that as long as the request didn't encounter an error, I consider the request a success and I'm going to handle the result in my response serializer. However, the validation APIs exist if you decide that you'd prefer to have Alamofire hand you an error in your response serializer if the response wasn't formatted the way you wanted. This has always been a choice up to the user.
Now at some point in the Alamofire releases, we realized that you always want to have access to the data that came back from the server in a success or failure case for the exact reasons you have all put in here. It can be useful! So as you can see, all the response serializers hand you back the server data directly regardless of what the result type is.
Hopefully that helps.
Cheers. 🍻
@cnoon, the data is not gone, but it's changed. In my example above It was "Unsupported grant type" from the server, but was changed to "status code was unacceptable: 400" by AF 3, which is indeed useless / redundant because it could be inferred by response.response!.statusCode
. The server told me why it is 400 status code which is useful but was changed to something useless. Correct me if I am wrong.
@tylerlong Try this
if let responseData = response.data {
let responseDataString = NSString(data: responseData, encoding:NSUTF8StringEncoding)
print(responseDataString)
}
Does that print the JSON, you expected?
Thanks @cnoon somehow I missed "data" by itself in the response..still new to debugging in Xcode I guess. I still think it's sort of strange for the API to change responseData / responseDataString and instead have you look at "data" for what you were originally returning from the backend. I was initially just paying attention to statusCode, json, msg, responseData & responseDataString. Perhaps I can help contribute to the docs to ensure no one else gets confused, clearly it's quite a few of us. 👍
The above worked @tobiasoleary and I'm able to see the correct response. @tylerlong you should be able to do the same. If not please let me know and I can try and help.
Cheers,
Gaurav.
@tylerlong...see @tobiasoleary's comment. Also re-read mine again. You're not looking at the data
property, you're looking at what's being printed out.
Guys I've got your point. But why is it behaving like this, so weird. There are other 4 people in this thread who were confused by it. debugPrint
gave me the illusion that response.result.value
contained message from server.
Thank you for the clarification!
I've added a Stackoverflow question about similar to this and Mr. Noon responded.
Also I've added a feature request that I think could be helpful. If any of you agree, please +1.
Thats helped me:
do {
let errorResponse = error as? Moya.MoyaError
if let body = try errorResponse?.response?.mapJSON(){
print(body) // response here
}
} catch {
print(error)
}
Most helpful comment
So to all of you convinced "the data is gone"...it's not.
Response Struct
The data is ALWAYS passed back to you in EVERY response serialization closure as part of the
Response
object in AF 3. Take a look at theResponse
struct:Is the
data
property not clear? Did anyone think to check it? Notice the[Data]: 83 bytes
that keep getting printed out when you usedebugPrint
@tylerlong and @gchaturvedi? Come on guys, help yourselves out a bit here...Validation
To your last point @tylerlong:
How is that "useless"? The error tells you "exactly" what went wrong with the request. You told Alamofire to validate the request, it did and told you why it failed.
History Lesson
If you don't run validation on the response, you're saying that as long as the request didn't encounter an error, I consider the request a success and I'm going to handle the result in my response serializer. However, the validation APIs exist if you decide that you'd prefer to have Alamofire hand you an error in your response serializer if the response wasn't formatted the way you wanted. This has always been a choice up to the user.
Now at some point in the Alamofire releases, we realized that you always want to have access to the data that came back from the server in a success or failure case for the exact reasons you have all put in here. It can be useful! So as you can see, all the response serializers hand you back the server data directly regardless of what the result type is.
Hopefully that helps.
Cheers. 🍻