Dynamically set the URL with ngResource

By Dave Ceddia

Here’s a problem I ran into the other day:

I’m working against a REST API that requires the current username in the URI like this: /api/~username/articles/2 - how can I extend ngResource to dynamically send the current username with every request?

ngResource is a very useful tool, and a nice way of abstracting away a lot of boilerplate code if you’re working with a REST API. Customizing your resources beyond the basics can sometimes be complicated though. The official docs are always a good starter point, but sometimes they’re a little obscure.

In this particular case, looking at the docs gave me an idea for a solution. The paramDefaults argument is what ngResource uses to “fill in the blanks” in your URLs. Those fill-in spots are prefixed by :, like this:

/api/~:username/articles/:id

This URL has 2 parameters: username and id. Once they’re filled in, you’ll get something like /api/~dave/articles/7.

In order to get ngResource to fill in the username automatically for you, perhaps based on some authorization service you already have, you can pass a function as the value of one of the parameter defaults, like this:

angular.factory('Article', function($resource, Authorization) {
    return $resource('/api/~:username/articles/:id', 
    // 2nd argument is paramDefaults.
    {
        id: '@id',
        // This should call currentUser() to obtain the username
        // before every request
        username: Authorization.currentUser
    });
});

For completeness, we’ll just assume you have a factory called Authorization that looks something like this:

angular.factory('Authorization', function() {
    var api = {};

    api.currentUser = function() {
        // Return the username somehow
        return 'dave';
    };

    return api;
});

And that should about do it. You can now inject your Article resource wherever you need it, and when you retrieve one by calling Article.get({id: 3}), ngResource will make a request to /api/~dave/articles/3.

Check out an example of it on Plnkr. To see it working, open up the debug console and watch the Network tab. Click the button and you should see a failed request for a URL with the username in it. In real life, your server would need to handle this route ;)