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