Search code examples
javascriptangularjsangularjs-service

How to write services with $q and $http calls without being repetitive


I'm trying to figure out an elegant way to write AngularJS services without being so repetitive with the $q syntax.

Currently, I'm writing services like follows:

(function() {

    function ServiceFactory($q, $timeout, $http) {
        return {
            getFoo: function() {
                var deferred = $q.defer();

                $timeout(function() {
                    $http.get('/the/foo/thing').then(function(response) {
                        if (response.isError) {
                            deferred.reject();
                        } else {
                            deferred.resolve(response.data.foo);
                        }
                    }, function() {
                        deferred.reject();
                    });
                });

                return deferred.promise;
            }
        };
    }

    angular.module('myapp').service('MyService', ['$q', '$timeout', '$http', ServiceFactory]);

}.call(this));

It works very well, buy I'm always writing down a bunch of code just to delay $http.get and expose a Promise. Sometimes I will have some extra stuff into success callback, like handling data, creating a different response object... But most of the time, is just like the code above: call $q.defer + $http.get().then... + return promise

So, I'm thinking about a way to clean up/reduce the code without affecting the clarity of what I'm doing, e.g if another developer open the file, it should not be a mystery.

As a side note, the $http service here is actually a decorator, handling server responses to give me a more structured object with things like response.isError and response.data.

Also, I have seen a similar solution in another question {1}, but this is not as same. Just returning the response of $http.get().then() will expose the entire response to controllers on response, and it is not the desired effect. Instead, when I call MyService.getFoo().then(...), I'm expecting a foo object as a response from service, fed by server via response.data.foo, or a call to errorCallback.

I've forgot to mention: my server is not RESTful, so $resource is not an option right now. My URLs are more like /thing/get/:id, /thing/do-stuff/:id.

{1} Similar question


Solution

  • After thinking for a while, I figured out a better way to write the services. I've done some changes to $http response, and now my implementation is returning a Promise whenever a Controller calls http.get() or whatever http methods. With this implementation, I've reduced the methods' code to two or three lines per request in most of the cases. Now I should try to use the AngularJS decorator setup.

    A working example is here:

    http://embed.plnkr.co/p4EHQAbE40XWXjBWqjIM/preview