34

My api requires a trailing slash for api calls. I was wondering how to pull that off with angular.

So i need to be able to access /tasks/ or a /tasks/xxxx/. I attempted to do it via:

angular.module('taskServices', ['ngResource']).
        factory('Tasks', function($resource){
            return $resource('/tasks/:task_id/', {}, {
                 query: {method:'GET', 
                         params:{},
                         isArray:true}
            });
 });

and a

$scope.tasks = Tasks.query(); 

But it results in a /tasks or a tasks/xxx query.

How can i force it to always be /tasks/ and /tasks/xxx/

Nix
  • 57,072
  • 29
  • 149
  • 198

9 Answers9

65

This seems to have been fixed: https://github.com/angular/angular.js/pull/5560

You can now configure it this way:

app.config(function($resourceProvider) {
  $resourceProvider.defaults.stripTrailingSlashes = false;
});
Marco Fucci
  • 1,834
  • 2
  • 18
  • 21
  • Thanks so much for the heads up. – Amyth Sep 06 '16 at 23:43
  • getting the error as TypeError: Cannot set property 'stripTrailingSlashes' of undefined –  Sep 27 '16 at 16:19
  • Note that you don't have to add this to your app it can be added to your resources module as well: `angular.module('myresources',['ngResource']) .config(function($resourceProvider) { $resourceProvider.defaults.stripTrailingSlashes = false; })` – Ehsan88 Mar 20 '20 at 08:02
35

The trailing slash is explicitly removed in this line of AngularJS source code. I'm not fully sure what was the rationale behind this code but there is already an issue opened for this: https://github.com/angular/angular.js/issues/992

As noted in the mentioned issue the $resource factory is great for RESTful endpoints that conform to a certain specification. While $resource will do do great job talking to back-ends conforming to a this specification, it has limitations that might rule it out for back-ends that don't obey a contract expected by the $resource. In such a case the best way forward is to switch to using the lower-level $http service as noted in this question: Recommended way of getting data from the server

$http is a very powerful and flexible service and allows full control over URLs, parameters sent etc.

Community
  • 1
  • 1
pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
20

adding a space at the very end of the url template works here (tested with angular 1.2.0):

{url: '/user/:id/ '}
mpaolini
  • 1,334
  • 10
  • 7
6

Adding the 2 back-slashes to escape the trailing slash on the URL worked for me on Chrome and Safari.

Firefox however decides that its a good idea to remove the trailing slash from the URL and encode the backslash that was escaping the forward slash to %5C...great :-) So in the example above you'd get http://example.com/controller/save%5C, which then 404s at the server.

I'm using Django+TastyPie for my project and need the trailing slash on the URL, I'll be looking to modify ngResource rather than dropping down to $http for everything as the lowest common denominator.

Andrew Hayes
  • 61
  • 1
  • 1
2

For AngularJS clients that use django-rest-framework, just use angular-django-rest-resource. Worked great.

Alexandre Simões
  • 1,229
  • 1
  • 10
  • 12
1

One can use http interceptors for all or specific urls, e.g. api urls:

app.factory('myHttpInterceptor', function ($q) {
    return {
        'request': function(config) {
            if (config.url.indexOf('/api/') != -1 && config.url.slice(-1) != '/') {
                config.url += '/';
            }
            return config || $q.when(config);
        }
    };
});

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
});
Max Tepkeev
  • 2,636
  • 1
  • 14
  • 12
0

As a work-around for this until/if they ever change the AngularJS source, I set a .htaccess rewrite rule to add a trailing slash to all incoming requests to the webserver.

RewriteCond %{REQUEST_URI} !(/$|\.)
RewriteCond %{REQUEST_METHOD} GET
RewriteRule (.*) %{REQUEST_URI}/ [R=301,L]

Downsides of this approach:

  • Network traffic of RESTful calls get 301 redirected, so you see requests being sent twice
  • This works only for GET requests (note the restriction in my example), if the rewrite receives POST, DELETE, PUT requests and redirects, it does so as a GET request of the same URL, which may not be what you want of course, since you lose your payload.
ako977
  • 692
  • 7
  • 8
0

I am able to get over the Firefox encoding issue by adding this to the ngResource before composing the final url:

url = url.replace(/\\/,"/");

This allows the slash escape fix for Chrome/Safari to work well on Firefox.

app.factory('Things', function($resource){
        return $resource('/api/v1/thing\\/', {}, {
              query: {method:'GET', params:{},isArray:true}});
        }); 
georges
  • 223
  • 1
  • 2
  • 9
-2

Vincent's escaping of the trailing slash (add two backslashes and a forward slash (http://example.com/controller/save\\/) to the end of the URL) worked for me.

Simon Guest
  • 2,112
  • 1
  • 15
  • 21