Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paramaterize the base URL in an Angular JS $resource

Tags:

angularjs

I'm using several Angular JS $resource definitions all of which retrieve their base URL from a configuration service. For example:

$resource(config.baseURL() + '/api/v2/foo/:id', {id: '@id'})

$resource(config.baseURL() + '/api/v2/bar/:id', {id: '@id'})

The reason this is done is that the base URL can be changed via a query string parameter when the application is first loaded.

I figured out that (obviously in retrospect) the URL used by the $resource is initialized just once so it's possible to get a race condition where the URL for a particular $resource is initialized before the base URL query string parameter is dealt with. So I tried to change the $resource declaration to this:

$resource(':baseURL/api/v2/foo/:id', {baseURL: config.baseURL(), id: '@id'})

Unfortunately the base URL is getting escaped – the // is converted to %2F%2F – so the whole URL then doesn't work properly.

Is there any way to suppress the escaping for that parameter? (or maybe a better way to solve the problem in general)?

like image 560
Rob Fletcher Avatar asked Nov 22 '13 10:11

Rob Fletcher


1 Answers

Another way you can tackle this is use a provider and config it in the config stage.

Here is an example of something similar I did a while back.

.provider('Environment', function () {
    var environments = {
        dev: {
            root: 'http://localhost',
            port: 3000,
            api: '/api',
            version: 'v1'
        }
    };
    var selectedEnv = 'dev';
    var self = this;

    this.setEnvironments = function (envs) {
        if (!Object.keys(envs).length)
            throw new Error('At least one environment is required!');

        environments = envs;
    };

    this.setActive = function (env) {
        if (!environments[env])
            throw new Error('No such environment present: ' + env);

        selectedEnv = env;
        return self.getActive();
    };

    this.getEnvironment = function (env) {
        if (!env)
            throw new Error('No such environment present: ' + env);
        return environments[env];
    };

    this.getActive = function () {
        if (!selectedEnv)
            throw new Error('You must configure at least one environment');

        return environments[selectedEnv];
    };

    this.getApiRoute = function () {
        var active = self.getActive();
        return active.root + (active.port ? ':' + active.port : '') +
            active.api + (active.version ? '/' + active.version : '');
    };

    this.$get = [function () {
        return self;
    }];
})

Then in the config phase:

.config(function (EnvironmentProvider) {

    EnvironmentProvider.setEnvironments({
        dev: {
            root: 'http://10.0.0.3',
            api: '/api',
            version: 'v1'
        },
        localonly: {
            root: 'http://localhost',
            api: '/api',
            version: 'v1'
        },
        prod: {
            root: 'https://myapp.mybackend.com',
            api: '/api',
            version: 'v1'
        }
    });

    //Set prod as the active schema
    EnvironmentProvider.setActive('prod');
});

Later in some controller/service/factory:

.factory('API',function($resource, Environment){
 return {
  User: $resource(Environment.getApiRoute() + '/users/:id', {id: '@_id'}),
  OtherResource: $resource(Environment.getApiRoute() + '/otherresource/:id', {id: '@_id'})
 }
});
like image 198
Muli Yulzary Avatar answered Oct 19 '22 10:10

Muli Yulzary