0

I have a little abstraction I wrote around $http that I use to make calls from a security service. The problem I am having is that during a request that results in a 401, the deferred does not seem to propogate correctly.

I am using it like so, and even if it is a 401 it alerts good... I would expect this to alert bad.

security.login('test', 'password').then(function (r) {
            alert('good');
        }, function (r) {
            alert('bad');
        });

Http Wrapper

angular.module('app').provider('http', function () {
    return {
        $get: ['$http', 'url', function ($http, url) {
            function http(config) {
                config.headers = {
                    'X-Requested-With': 'XMLHttpRequest'
                };
                config.url = url.formatUrl(config.url);
                return $http(config);
            }

            return {
                delete: function (url, data) {
                    return http({ url: url, data: data, method: 'DELETE' });
                },
                get: function (url) {
                    return http({ url: url, method: 'GET' });
                },
                post: function (url, data) {
                    return http({ url: url, data: data, method: 'POST' });
                },
                put: function (url, data) {
                    return http({ url: url, data: data, method: 'PUT' });
                }
            };
        }]
    };
});

Security Service

function User() {
    this.displayName = '';
    this.permissions = [];
}

angular.module('app').provider('security', function () {
    var _user = new User();

    return {
        $get: ['$rootScope', '$q', 'cookie', 'http', 'statePermissions', function ($rootScope, $q, cookie, http, statePermissions) {
            function login(params) {
                return http.post('SS/auth', params).then(function (response) {
                    cookie.set('authToken', response.data.authToken);
                    _user = response.data;

                    $rootScope.$broadcast('event:loginSuccessful', _user);

                    return response;

                }, function (response) {
                    cookie.expireNow('authToken');
                    _user = new User();

                    $rootScope.$broadcast('event:loginUnsuccessful', _user);

                    $q.reject(response);

                });
            }

            return {
                doesAuthTokenExist: function () {
                    return angular.isDefined(cookie.get('authToken'));
                },
                getUser: function () {
                    return _user;
                },
                isUserAuthorizedForPermission: function (permission) {
                    var x;

                    for (x = 0; x < _user.permissions.length; x++) {
                        if (_user.permissions[x] === permission) {
                            return true;
                        }
                    }

                    return false;
                },
                isUserAuthorizedForState: function (stateName) {
                    if (angular.isDefined(statePermissions[stateName])) {
                        return this.isUserAuthorizedForPermission(statePermissions[stateName]);
                    }

                    return true;
                },
                login: function (userName, password) {
                    return login({ username: userName, password: password });
                },
                loginWithAuthToken: function () {
                    var authToken = cookie.get('authToken');

                    return login({ provider: 'token', authToken: authToken });
                },
                logout: function () {
                    return http.post('SS/auth/logout').then(function () {
                        cookie.expireNow('authToken');
                        _user = new User();

                        $rootScope.$broadcast('event:logoutSuccessful', _user);

                        return true;
                    });
                }
            };
        }]
    };
});
Sam
  • 15,336
  • 25
  • 85
  • 148
  • What is a status of the response? Try `console.log(r.status)` instead of alert (regardless of callback type) and paste here result please – Sean Doe Jan 02 '14 at 23:04
  • btw, I found discussion about handling 401 response, it should help you: http://stackoverflow.com/questions/11971213/error-401-handling-with-angularjs – Sean Doe Jan 02 '14 at 23:07

1 Answers1

1

Your $http wrapper looks like it's duplicating the functionality of angular's $resource service. Check out the documentation here: http://docs.angularjs.org/api/ngResource.$resource

After a brief look at your code, it seems like the problem could be with how you're using $q. Try rewriting your login method along these lines.

With insight from here:
http://docs.angularjs.org/api/ng.$q
http://docs.angularjs.org/api/ng.$http

function login(params) {

            var deferred = $q.defer();

            http.post('SS/auth', params).success(function (response) {
                cookie.set('authToken', response.data.authToken);
                _user = response.data;

                $rootScope.$broadcast('event:loginSuccessful', _user);

                deferred.resolve(response);

            }).error(function (error) {
                cookie.expireNow('authToken');
                _user = new User();

                $rootScope.$broadcast('event:loginUnsuccessful', _user);

                deferred.reject(error);

            });

            return deferred.promise;
        }

Also, just curious why you are using providers here as it's not obvious to me?

tenthfloor
  • 160
  • 9
  • I realized I was returning the `.then()` instead of the promise from the `login()` method... I use providers for all my services, I was under the understanding that all services, factories, etc are providers under the sheets anyways... In this instance I need to configure some settings that are yet to be implemented. – Sam Jan 03 '14 at 03:24