Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error handling in Alamofire

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.

like image 571
Paymahn Moghadasian Avatar asked Mar 13 '15 04:03

Paymahn Moghadasian


People also ask

Is Alamofire asynchronous?

Networking in Alamofire is done asynchronously. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are very good reasons for doing it this way. None of the response handlers perform any validation of the HTTPURLResponse it gets back from the server.

What is the use of Alamofire in Swift?

Alamofire is a networking library written in Swift. You use it to make HTTP(S) requests on iOS, macOS and other Apple platforms. For example, to post data to a web-based REST API or to download an image from a webserver. Alamofire has a convenient API built on top of URLSession (“URL Loading System”).

What is the advantage of Alamofire?

Advantages of Using AlamofireUsing Alamofire will give a cleaner project. API call interactions (POST/GET/PUT/etc.) will be easier and more understable. Alamofire simplifies a number of common networking tasks that makes development faster and easier.


1 Answers

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...299
  • Content-Type - This header in the response must match the Accept header in the original request

You 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.

like image 195
cnoon Avatar answered Oct 03 '22 14:10

cnoon