Is it possible to use parameterized URL templates with angular $http service
Asked Answered
M

2

16

I'm using $resource for my RESTful api's and love the parameterized URL template for example 'api/clients/:clientId'

This works great for CRUD operations. Some of my api's however are just reports or read-only end points without the need for the full RESTful treatment. I felt it was overkill to use $resource for those and instead used a custom data service with $http.

The only drawback is I lose the parameterized URL templates. I would love to define a url like'api/clients/:clientId/orders/:orderId' and just pass { clientId: 1, orderId: 1 }. I realize I can build the url dynamically but was hoping $http supported the parameterized template and I just haven't found it yet.

All the best

UPDATE 7/5

The word I was missing in my searches is 'Interpolate'. More information comes up when I search for 'url interpolation in angular $http'. The short answer looks to be 'No' $http doesn't support url interpolation. There are a few fairly easy ways to accomplish this however.

1. Use $interpolate:

Documentation for $interpolate here

var exp = $interpolate('/api/clients/{{clientId}}/jobs/{{jobId}}', false, null, true);
var url = exp({ clientId: 1, jobId: 1 });


2. Write your own url interpolation function

Ben Nadel has a great post on this exact topic here.


3. Steal the functionality right out of angular-resource

Check out setUrlParams on Route.prototype in angular-resource.js. It is fairly straightforward.

Sample data service using $interpolate

(function () {
    'use strict';

    var serviceId = 'dataservice.jobsReports';

    angular.module('app').factory(serviceId, ['$http', '$interpolate', function ($http, $interpolate) {

        var _urlBase = 'http://localhost:59380/api';
        var _endPoints = {
            getJobsByClient: {
                url: 'Clients/{{clientId}}/Jobs',
                useUrlInterpolation: true,
                interpolateFunc: null
            }
        };

        // Create the interpolate functions when service is instantiated
        angular.forEach(_endPoints, function (value, key) {
            if (value.useUrlInterpolation) {
                value.interpolateFunc = $interpolate(_urlBase + '/' + value.url, false, null, true);
            }
        });

        return {
            getJobsByClient: function (clientId) {
                var url = _endPoints.getJobsByClient.interpolateFunc({ clientId: clientId });
                return $http.get(url);
            }
        };

    }]);

})();
Magnoliamagnoliaceous answered 5/7, 2015 at 13:1 Comment(4)
Since you've answered your own question, I would recommend adding your answer and then accepting it.Doublespace
As @Doublespace noted. Your solution should be moved into its own answer to separate it from the question and you can mark it as answeredAngularity
4. Use ES2015's ${}?Schismatic
yes we can.. am using spring mvc for backend. And with parameterized url request. I can get parameters from that requestFidelia
C
2

To prevent this being "unanswered" when it has been answered ...

1. Use $interpolate:

Documentation for $interpolate here

var exp = $interpolate('/api/clients/{{clientId}}/jobs/{{jobId}}', false, null, true);
var url = exp({ clientId: 1, jobId: 1 });


2. Write your own url interpolation function

Ben Nadel has a great post on this exact topic here.


3. Steal the functionality right out of angular-resource

Check out setUrlParams on Route.prototype in angular-resource.js. It is fairly straightforward.

Sample data service using $interpolate

(function () {
    'use strict';

    var serviceId = 'dataservice.jobsReports';

    angular.module('app').factory(serviceId, ['$http', '$interpolate', function ($http, $interpolate) {

        var _urlBase = 'http://localhost:59380/api';
        var _endPoints = {
            getJobsByClient: {
                url: 'Clients/{{clientId}}/Jobs',
                useUrlInterpolation: true,
                interpolateFunc: null
            }
        };

        // Create the interpolate functions when service is instantiated
        angular.forEach(_endPoints, function (value, key) {
            if (value.useUrlInterpolation) {
                value.interpolateFunc = $interpolate(_urlBase + '/' + value.url, false, null, true);
            }
        });

        return {
            getJobsByClient: function (clientId) {
                var url = _endPoints.getJobsByClient.interpolateFunc({ clientId: clientId });
                return $http.get(url);
            }
        };

    }]);

})();
Capita answered 18/3, 2016 at 9:39 Comment(1)
Since it's from OP's question, you should make the answer a community wiki and then, we could remove the answer from the question (as it wouldn't be seen as a rep grab then).Multi
C
0

For URL templateing, there is a clearly defined recommandation: RFC 6570

You can find one implementation on Github : bramstein/url-template

It is quite simple. Here is an AngularJS service making use of a library implementing RFC 6570 standard:

var app=angular.module('demo',[]);


app.service('UserStore',function () {
  var baseUrl=urltemplate.parse('/rest/v1/users{/_id}');
  return {
    load:function(id){
      return $http.get(baseUrl.expand({_id:id}));
    },
    save:function (profile) {
      return baseUrl.expand(profile);
      //return $http.post(baseUrl.expand(profile),profile);
    },
    list:function (id) {

    }
  }
});

app.controller('demoCtrl',function(UserStore){
  this.postUrlOfNewUser=UserStore.save({name:"jhon"});
  this.postUrlOfExistingUser=UserStore.save({_id:42,name:"Arthur",accessory:"towel"});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.rawgit.com/bramstein/url-template/master/lib/url-template.js"></script>
<div ng-app="demo">
  <div ng-controller="demoCtrl as ctrl">
    <div>New user POST URL: {{ctrl.postUrlOfNewUser}}</div>
    <div>Existing user POST URL: {{ctrl.postUrlOfExistingUser}}</div>
  </div>
</div>
<script>
</script>

As you can see, the standard even handle optional PATH component. It make it a breeze !

And you can also use "." or ";" -- for matrix notation and even expand query strings!

Chlorobenzene answered 28/9, 2016 at 20:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.