I have the HTTP code in an AngularJS controller:
$http.post('/api/users/authenticate', {email: $scope.email, password: $scope.password})
.success(function (data, status, headers, config) {
authService.login($scope.email);
$state.go('home');
})
.error(function (data, status, headers, config) {
$scope.errorMessages = data;
$scope.password = "";
});
In the success case, the server will respond with a JSON representation of a user. In the error case the server will respond with a simple string such as User not found
which can be accessed through the data
parameter.
I'm having trouble figuring out how to do something similar in Alamofire. Here's what I have right now:
@IBAction func LoginPressed(sender: AnyObject) {
let params: Dictionary<String,AnyObject> = ["email": emailField.text, "password": passwordField.text]
Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params)
.responseJSON {(request, response, data, error) in
if error == nil {
dispatch_async(dispatch_get_main_queue(), {
let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController;
self.presentViewController(welcome, animated: true, completion: nil);
})
}
else{
dispatch_async(dispatch_get_main_queue(), {
// I want to set the error label to the simple message which I know the server will return
self.errorLabel.text = "something went wrong"
});
}
}
}
I have no idea if I'm handling the non-error case correctly either and would appreciate input on that as well.
You are are on the right track, but you are going to run into some crucial issues with your current implementation. There are some low level Alamofire things that are going to trip you up that I want to help you out with. Here's an alternative version of your code sample that will be much more effective.
@IBAction func loginPressed(sender: AnyObject) {
let params: [String: AnyObject] = ["email": emailField.text, "password": passwordField.text]
let request = Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params)
request.validate()
request.response { [weak self] request, response, data, error in
if let strongSelf = self {
let data = data as? NSData
if data == nil {
println("Why didn't I get any data back?")
strongSelf.errorLabel.text = "something went wrong"
return
} else if let error = error {
let resultText = NSString(data: data!, encoding: NSUTF8StringEncoding)
println(resultText)
strongSelf.errorLabel.text = "something went wrong"
return
}
var serializationError: NSError?
if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) {
println("JSON: \(json)")
let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController
self.presentViewController(welcome, animated: true, completion: nil)
} else {
println("Failed to serialize json: \(serializationError)")
}
}
}
}
Validation
First off, the validate
function on the request will validate the following:
HTTPStatusCode
- Has to be 200...299Content-Type
- This header in the response must match the Accept
header in the original requestYou can find more information about the validation in Alamofire in the README.
Weakify / Strongify
Make sure to weak self and strong self your closure to make sure you don't end up creating a retain cycle.
Dispatch to Main Queue
Your dispatch calls back to the main queue are not necessary. Alamofire guarantees that your completion handler in the response
and responseJSON
serializers is called on the main queue already. You can actually provide your own dispatch queue to run the serializers on if you wish, but neither your solution or mine are currently doing so making the dispatch calls to the main queue completely unnecessary.
Response Serializer
In your particular case, you don't actually want to use the responseJSON
serializer. If you do, you won't end up getting any data back if you don't pass validation. The reason is that the response from the JSON serialization is what will be returned as the AnyObject
. If serialization fails, the AnyObject
will be nil and you won't be able to read out the data.
Instead, use the response
serializer and try to parse the data manually with NSJSONSerialization
. If that fails, then you can rely on the good ole NSString(data:encoding:)
method to print out the data.
Hopefully this helps shed some light on some fairly complicated ways to get tripped up.