$resource success callback returning $promise

Erik Olson picture Erik Olson · May 12, 2014 · Viewed 8.7k times · Source

Using Angular 1.2.14, $resource's success callback should return an object, but it sometimes gets a $promise. The node/express web service is returning null, but Angular interprets it as a $promise. When a non-null is returned from the web service, the success callback gets the object as expected.

$resource('/api/users/:userId/team').get({ userId: userId }, function(team) {
    console.log('team: ', team);                
}, function(err) {
    console.log('err: ', err);
});

The value of team (the parameter to the success callback) is:

$promise: Object
    catch: function (callback) {
    finally: function (callback) {
    then: function (callback, errback, progressback) {
    __proto__: Object
    $resolved: true
__proto__: Resource
    $delete: function (params, success, error) {
    $get: function (params, success, error) {
    $query: function (params, success, error) {
    $remove: function (params, success, error) {
    $save: function (params, success, error) {
    constructor: function Resource(value) {
    __proto__: Object

Why is the success callback getting a $promise and not an object?

Answer

Benjamin Gruenbaum picture Benjamin Gruenbaum · May 12, 2014

Why is the success callback getting a $promise and not an object?

Because it made a successful HTTP request and received a response which happened to be null. Returning null is not how we signal to an HTTP server that our value is invalid - rather, we return the appropriate status code to indicate failure - see this article.

How do I fix it from the client?

Well, you didn't ask this, but I assume this is what you actually care about, since $resource returns a promise, you can transform it yourself, via a decorator for example.

If you don't need re-usability you can simply do:

$resource('/api/users/:userId/team').get({ userId: userId }).then(function(res){
    if(res === null) return $q.reject("Error, server returned null");
    return res;
}).then(function(team) {
    console.log('team: ', team);                
}, function(err) {
    console.log('err: ', err);
});

Otherwise, you can wrap it in a more general method:

function notNull(prom){
    return prom.then(function(res){
        if(res === null) return $q.reject("Error, got null);
        return res;
    });
};

Which would let you do:

notNull($resource('/api/users/:userId/team').get({ userId: userId })).then(function(res){
      // server returned not null.
}).catch(function(e){
     // returned null, or other server error, or error in previous then handler.
});