Getting the returned error message from Alamofire - swift

I am struggling to get the json error message returned using Alamofire and their .success / .failure method.
Before using this I could use response.result.value and get the returned error message but now I am validating the status code .validate(statusCode: 200..<300).
Have tried several things to receive the error but it always produces nil or just the status code.
Alamofire.request(url, method: .post, parameters: body, encoding: JSONEncoding.default)
.validate(statusCode: 200..<300)
.responseJSON { response in
switch response.result {
case .success:
//Other stuff
case .failure(let error):
print(response.result.value) //Produces nil when there is an error
print(error.localizedDescription)
print(response.result.error.customMirror)
print(response.result.error.debugDescription)
print(response.result.error.unsafelyUnwrapped)
print(response.result.error?.localizedDescription)
}
}
How can I get the error json? It is getting returned as such.
{
"status": "error",
"message": "Incorrect Password"
}

take that .validate() out. You will see more detailed description.

Related

Swift - Alamofire returns "Invalid request format." when I try to upload file to pinata

print(element) print following
error = "Invalid request format."
Although the response.result is success.
I don't know what to do... appreciate any help.
let request = AF.request("https://api.pinata.cloud/pinning/pinFileToIPFS",
method: .post,
parameters: data,
encoding: JSONEncoding.default,
headers: [
"Content-Type": "multipart/form-data;boundary=nadeshiko_data_boundary",
"pinata_api_key": "myAPIKey",
"pinata_secret_api_key": "mySecretApiKey"
])
request.responseString { response in
print("responseString responseee", response)
switch response.result {
case .success(let element):
print(element)
case .failure(let error):
print("failure", error)
}
}
I asked to pinata support.
Turns out I was trying to upload JSON file where I have to upload a File.

Swift Alamofire post "Extra argument in call"

I want to post some xml to an url. This is my code:
func post(){
var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Devices><Device><ID>EZR0114AF</ID><HEATAREA nr=\"4\"><T_TARGET>17.0</T_TARGET></HEATAREA></Device></Devices>"
Alamofire.request(urlPost, .post, parameters: data, encoding: .utf8, headers: nil).response { (response) in
print(response.data)
print(response.error)
print(response.response)
}
}
But I get a Syntax error: Extra argument in call. I have no idea what is missing, I tried a lot but nothing works. Any ideas?
Try changing the syntax to
let urlString = "XXXXXXXXX"
Alamofire.request(urlString, method: .post, parameters: ["id": "1,2,3,4"] ,encoding: JSONEncoding.default, headers: nil).responseString {
response in
switch response.result {
case .success(let responseString1):
print("the response is: \(responseString1)")
break
case .failure(let error):
print("The error is: \(error)")
}
}

Swift catching error

Why is
if error = response.result.error else {
print (error)
}
Not allowed and throws an error within the function below? I would have expected it should go through well.
Alamofire.request(Router.RegisterUser(parameters))
.validate()
.responseJSON(completionHandler: { (response) -> Void in
if let receivedData = response.result.value {
let json = JSON(receivedData)
// Check for error in JSON
if let message = json["error"]["message"].string {
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: message)
print(error)
return
}
completionHandler(.Success(true), response: JSON(receivedData))
}
if error = response.result.error else {
print (error)
}
})
I use the validate function to avoid successful responses to the completionhandler, when indeed an error code is returned by the server. The problem now is, that the only error I can currently receive is the one, thrown by validate(). But I use error handling in my API as well and will return a suitable error message to the user.
Error Domain=com.alamofire.error Code=-6003 "Response status code was
unacceptable: 400" UserInfo={NSLocalizedFailureReason=Response status
code was unacceptable: 400}
How can I achieve this now? As by using validate, the response will never get processed as far as I understand?
Alamofire.request(Router.RegisterUser(parameters))
.validate()
.responseJSON(completionHandler: { (response) -> Void in
switch(response.result) {
case .Success(let response):
print(response)
case .Failure(let error):
print("FAILURE: \(error)")
}
})
}
There seems to be 2 issues in your code:
You are missing a let or guard to check if there is an error.
print(error) should be inside if as you are checking error is not nil and trying to print error in else which will be nil.

Alamofire error is always nil, while request fails

In case of 400(bad request) or 403(unauthorized) I can grab info about fail only from response, while error,passed in param is always nil - do it needs any extra setup?
Alamofire.request(Router.SignIn(emailField.text, passwordField.text)).response { (request, response, data, error) in
println(error)
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}
UPD: as mattt advised added valide like this:
Alamofire.request(UdacityRouter.SignIn(emailField.text, passwordField.text)).validate().response
in
println(error)
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}
As result I received "Optional("The operation couldn’t be completed. (com.alamofire.error error -1.)")" What is far away from meaningfull explanation of failure.. I wonder why I can't simply get error with a simple failure explanation as AFNetworking does..
Need to add .validate() because of by default, Alamofire treats any completed request to be successful, regardless of the content of the response.
From Alamofire documentation:
Validation
By default, Alamofire treats any completed request to be successful,
regardless of the content of the response. Calling validate before a
response handler causes an error to be generated if the response had
an unacceptable status code or MIME type.
Manual Validation
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.response { _, _, _, error in
println(error)
}
Automatic Validation
Automatically validates status code within 200...299 range, and that
the Content-Type header of the response matches the Accept header of
the request, if one is provided.
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.validate()
.response { _, _, _, error in
println(error)
}

Swift Alamofire: How to get the HTTP response status code

I would like to retrieve the HTTP response status code (e.g. 400, 401, 403, 503, etc) for request failures (and ideally for successes too). In this code, I am performing user authentication with HTTP Basic and want to be able to message the user that authentication failed when the user mistypes their password.
Alamofire.request(.GET, "https://host.com/a/path").authenticate(user: "user", password: "typo")
.responseString { (req, res, data, error) in
if error != nil {
println("STRING Error:: error:\(error)")
println(" req:\(req)")
println(" res:\(res)")
println(" data:\(data)")
return
}
println("SUCCESS for String")
}
.responseJSON { (req, res, data, error) in
if error != nil {
println("JSON Error:: error:\(error)")
println(" req:\(req)")
println(" res:\(res)")
println(" data:\(data)")
return
}
println("SUCCESS for JSON")
}
Unfortunately, the error produced does not seem to indicate that an HTTP status code 409 was actually received:
STRING Error:: error:Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo=0x7f9beb8efce0 {NSErrorFailingURLKey=https://host.com/a/path, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://host.com/a/path})
req:<NSMutableURLRequest: 0x7f9beb89d5e0> { URL: https://host.com/a/path }
res:nil
data:Optional("")
JSON Error:: error:Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo=0x7f9beb8efce0 {NSErrorFailingURLKey=https://host.com/a/path, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://host.com/a/path})
req:<NSMutableURLRequest: 0x7f9beb89d5e0> { URL: https://host.com/a/path }
res:nil
data:nil
Additionally, it would be nice to retrieve the HTTP body when an error occurs because my server-side will put a textual description of the error there.
Questions
Is it possible to retrieve the status code upon a non-2xx response?
Is it possible to retrieve the specific status code upon a 2xx response?
Is it possible to retrieve the HTTP body upon a non-2xx response?
Thanks!
For Swift 3.x / Swift 4.0 / Swift 5.0 users with Alamofire >= 4.0 / Alamofire >= 5.0
response.response?.statusCode
More verbose example:
Alamofire.request(urlString)
.responseString { response in
print("Success: \(response.result.isSuccess)")
print("Response String: \(response.result.value)")
var statusCode = response.response?.statusCode
if let error = response.result.error as? AFError {
statusCode = error._code // statusCode private
switch error {
case .invalidURL(let url):
print("Invalid URL: \(url) - \(error.localizedDescription)")
case .parameterEncodingFailed(let reason):
print("Parameter encoding failed: \(error.localizedDescription)")
print("Failure Reason: \(reason)")
case .multipartEncodingFailed(let reason):
print("Multipart encoding failed: \(error.localizedDescription)")
print("Failure Reason: \(reason)")
case .responseValidationFailed(let reason):
print("Response validation failed: \(error.localizedDescription)")
print("Failure Reason: \(reason)")
switch reason {
case .dataFileNil, .dataFileReadFailed:
print("Downloaded file could not be read")
case .missingContentType(let acceptableContentTypes):
print("Content Type Missing: \(acceptableContentTypes)")
case .unacceptableContentType(let acceptableContentTypes, let responseContentType):
print("Response content type: \(responseContentType) was unacceptable: \(acceptableContentTypes)")
case .unacceptableStatusCode(let code):
print("Response status code was unacceptable: \(code)")
statusCode = code
}
case .responseSerializationFailed(let reason):
print("Response serialization failed: \(error.localizedDescription)")
print("Failure Reason: \(reason)")
// statusCode = 3840 ???? maybe..
default:break
}
print("Underlying error: \(error.underlyingError)")
} else if let error = response.result.error as? URLError {
print("URLError occurred: \(error)")
} else {
print("Unknown error: \(response.result.error)")
}
print(statusCode) // the status code
}
(Alamofire 4 contains a completely new error system, look here for details)
For Swift 2.x users with Alamofire >= 3.0
Alamofire.request(.GET, urlString)
.responseString { response in
print("Success: \(response.result.isSuccess)")
print("Response String: \(response.result.value)")
if let alamoError = response.result.error {
let alamoCode = alamoError.code
let statusCode = (response.response?.statusCode)!
} else { //no errors
let statusCode = (response.response?.statusCode)! //example : 200
}
}
In the completion handler with argument response below I find the http status code is in response.response.statusCode:
Alamofire.request(.POST, urlString, parameters: parameters)
.responseJSON(completionHandler: {response in
switch(response.result) {
case .Success(let JSON):
// Yeah! Hand response
case .Failure(let error):
let message : String
if let httpStatusCode = response.response?.statusCode {
switch(httpStatusCode) {
case 400:
message = "Username or password not provided."
case 401:
message = "Incorrect password for user '\(name)'."
...
}
} else {
message = error.localizedDescription
}
// display alert with error message
}
Alamofire
.request(.GET, "REQUEST_URL", parameters: parms, headers: headers)
.validate(statusCode: 200..<300)
.responseJSON{ response in
switch response.result{
case .Success:
if let JSON = response.result.value
{
}
case .Failure(let error):
}
Best way to get the status code using alamofire.
Alamofire.request(URL).responseJSON {
response in
let status = response.response?.statusCode
print("STATUS \(status)")
}
Or use pattern matching
if let error = response.result.error as? AFError {
if case .responseValidationFailed(.unacceptableStatusCode(let code)) = error {
print(code)
}
}
you may check the following code for status code handler by alamofire
let request = URLRequest(url: URL(string:"url string")!)
Alamofire.request(request).validate(statusCode: 200..<300).responseJSON { (response) in
switch response.result {
case .success(let data as [String:Any]):
completion(true,data)
case .failure(let err):
print(err.localizedDescription)
completion(false,err)
default:
completion(false,nil)
}
}
if status code is not validate it will be enter the failure in switch case
In your responseJSON completion, you can get the status code from the response object, which has a type of NSHTTPURLResponse?:
if let response = res {
var statusCode = response.statusCode
}
This will work regardless of whether the status code is in the error range. For more information, take a look at the NSHTTPURLResponse documentation.
For your other question, you can use the responseString function to get the raw response body. You can add this in addition to responseJSON and both will be called.
.responseJson { (req, res, json, error) in
// existing code
}
.responseString { (_, _, body, _) in
// body is a String? containing the response body
}
Your error indicates that the operation is being cancelled for some reason. I'd need more details to understand why. But I think the bigger issue may be that since your endpoint https://host.com/a/path is bogus, there is no real server response to report, and hence you're seeing nil.
If you hit up a valid endpoint that serves up a proper response, you should see a non-nil value for res (using the techniques Sam mentions) in the form of a NSURLHTTPResponse object with properties like statusCode, etc.
Also, just to be clear, error is of type NSError. It tells you why the network request failed. The status code of the failure on the server side is actually a part of the response.
Hope that helps answer your main question.
I needed to know how to get the actual error code number.
I inherited a project from someone else and I had to get the error codes from a .catch clause that they had previously setup for Alamofire:
} .catch { (error) in
guard let error = error as? AFError else { return }
guard let statusCode = error.responseCode else { return }
print("Alamofire statusCode num is: ", statusCode)
}
Or if you need to get it from the response value follow #mbryzinski's answer
Alamofire ... { (response) in
guard let error = response.result.error as? AFError else { return }
guard let statusCode = error.responseCode else { return }
print("Alamofire statusCode num is: ", statusCode)
})
For Swift 2.0 users with Alamofire > 2.0
Alamofire.request(.GET, url)
.responseString { _, response, result in
if response?.statusCode == 200{
//Do something with result
}
}
For Swift 3.x / Swift 4.0 / Swift 5.0 users with Alamofire >= 5.0
Used request modifier to increase and decrease the timeout interval.
Alamofire's request creation methods offer the most common parameters for customization but sometimes those just aren't enough. The URLRequests created from the passed values can be modified by using a RequestModifier closure when creating requests. For example, to set the URLRequest's timeoutInterval to 120 seconds, modify the request in the closure.
var manager = Session.default
manager.request(urlString, method: method, parameters: dict, headers: headers, requestModifier: { $0.timeoutInterval = 120 }).validate().responseJSON { response in
OR
RequestModifiers also work with trailing closure syntax.
var manager = Session.default
manager.request("https://httpbin.org/get") { urlRequest in
urlRequest.timeoutInterval = 60
urlRequest.allowsConstrainedNetworkAccess = false
}
.response(...)
AF.request(url, method: .get).responseDecodable(of: Weather.self) { response in
switch response.result {
case .success(let data):
print(data)
var statusCode = response.response?.statusCode
if statusCode == 200 {
print(response)
}
case .failure(let error):
print(error)
}
}