Grouping back-end APIs

While using AngularJS's $http service I've found hard to manage all urls to backend - they're spread around controller's code. Sometimes they're even duplicated. Mostly all of them are in form of $http.get('/api/something').then(...).

To put all of them into different services sounds quite unreasonable: it is just one line of code with may be just small modifications (like adding header etc).

Other solution could be putting them into constants, but in this case I would still use $http.get(APIURLs.SomeURL) that looks like little bit verbose...

So the question is: what is the best way to manage URLs to back-end?

Currently I came up with idea of grouping them into servicies and expose them as calls to $http. Here is my solution: http://plnkr.co/edit/VjqXHBV54bmjKCuGJ4qX?p=preview

Service:

.factory('AdminAPI', function($http) {
   var apiMap = {
     'DeleteAuth': {url:'/api/oauth/delete',method:'PUT'},
     'GetInvalidUser': {url:'/api/users/invalid',method:'GET'},
     'CreateItem': {url:'/api/items/create',method:'POST'}     
   };
   var api = {};  
   var prepareCall = function(config) {
     return function(params) {  
       var requestConfig = angular.copy(config);
       if (config.method=='GET')
          requestConfig.params = params;
       else 
          requestConfig.data = params;       
       return $http(requestConfig);
     };
   };
   for(var name in apiMap) 
     api[name] = prepareCall(apiMap[name]);   
   return api;
});

And in controllers I do something like:

AdminAPI.DeleteAuth({data:123}).then(function(result) {
  //
});

In this case I have some abstraction (do not have to inject $http into controller), so unit-tests become little bit easier (I do not have to use $httpBackend service, just mock my service calls).

Make use of angular Module.constant:

  • Move reusable settings to single object;
  • Define angular module wrapping this object:

    angular.module('myApp.constants', []).constant('config', {
        ROUTES: {
           home: '/home.html',
           about: '/about.html'
        }
    });
    
  • load myApp.constants module into application with all the others:

    angular.module('myApp', [
        'myApp.constants',
        'myApp.services',
        'myApp.controllers',
        'myApp.filters',
        'myApp.directives'
    ]);
    

After that you can inject config dependency and access defined hash.

Good question. My suggested approach is to put the constants in a constantdeclaration like this:

angular.module('fooApp').constant('config', {
                                      api: {
                                        baseUrl: 'http://api.example.com/api',
                                        key: 'SECRET_API_KEY',
                                      }
});

And you could implement a httpResourceFactory that is responsible for creating $http or $resource references that points to different endpoints using the constants defined in config. This could be implemented in a service.

Then all API endpoint definitions can be put into a single service.

angular.module('fooApp').factory('dataService', ['httpResourceFactory',  function(httpResourceFactory) {

    var PUBLIC_API = {};

    PUBLIC_API.Orders = httpResourceFactory('/orders/:id');
    PUBLIC_API.Users = httpResourceFactory('/some-url/users/:id');


    return PUBLIC_API;

  }]);

Then in your controller you may inject dataService and do stuff like this:

$scope.users = dataService.Users.query();

Hope this clarified it. I'm in a hurry, so ask more concrete and I will provide more examples later on.