15

From where should REST API request be invoked from angular js?

I.e. from controller, module, service, factory. I am totally confused that what should be the right way for it?

phd
  • 82,685
  • 13
  • 120
  • 165
unknownbits
  • 2,855
  • 10
  • 41
  • 81

6 Answers6

12

Here's what I would regard as best practice:

  • Use a factory service to handle the mechanics of access to the RESTful web api
  • Inject the factory service into the controller that needs access
  • Use a promise in the factory to resolve or reject the response from the $http call
  • The promise allows the controller to determine how it should respond to the result of the RESTful call. For example, it may want to invoke a toast popup to notify the user of any problem.

This maintains good separation between the data service layer, the business logic and the front-facing UI. It also limits any consequences of changes to any one layer, to other layers.

John Kelleher
  • 411
  • 5
  • 7
11

You can use either resources, or build services that implement http calls.

If you want to use resources, remember:

  1. to include the angular-resource.js file which you can find here
  2. to include in your module declaration to include the ngResource module dependency like so: angular.module('myApp',['ngResource'])

After that you can declare a resource in this fashion:

function MyController($scope, $resource){
  var User = $resource('/user/:userId', {userId:'@id'});
  var user = User.get({userId:123}, function() {
    user.abc = true;
    user.$save();
  });
}

Alternatively, use services if you need a much deeper level of granularity such as

angular.module('myApp')
.factory('MyAPIService', function($http){
  var apiurl, myData;
  return {
    getData: function(){
      $http.get(apiurl)
      .success(function(data, status, config, headers){
        myData = data;
      })
      .error(function(){ //handler errors here
      });
    },
    data: function() { return myData; }
  };
});

I find services to be great because of the ability to share data between controllers, so you can inject them in a controller like so

myapp.controller('MyController', function($scope, MyAPIService){
  $scope.data = MyAPIService.data();
  // etc.

});
Joe Minichino
  • 2,793
  • 20
  • 20
  • 2
    I would go with Resources as they are made for that purpose. – maxdec Aug 30 '13 at 10:09
  • 3
    @maxdec yes, resources are made for that purpose but not all APIs are about CRUD'ing some object/model. There are far more complex scenarios which would be far-fetched with resources. – Joe Minichino Aug 30 '13 at 10:14
  • I agree but as we're talking about a RESTful api and the main principle of a REST api is to [provide access to resources](http://en.wikipedia.org/wiki/Representational_state_transfer#Central_principle), it would make sense to use the [$resource](http://docs.angularjs.org/api/ngResource.$resource) service :-) – maxdec Aug 30 '13 at 11:30
  • @maxdec can you please give me an example with resource? – unknownbits Sep 01 '13 at 16:07
  • here is a simple example :http://www.masnun.com/2013/08/28/rest-access-in-angularjs-using-ngresource.html – Adrien Mar 17 '14 at 11:00
3

This is how we do this, Write the http service as a factory method.

Edited as per comments to use Promise API

 var MyApp = angular.module('App', []);

 MyApp .factory('ApiFactory', ['$http',
        function ($http) {
            return {
               getUsers: function (rowcount) {
                var promise = $http.get('api/Users/' + rowcount) .then(function(response) {
                return response.data;
              }, function (error) {
                //error
            })
            return promise;
           }
         }
       }
   ]);

Now you can use it in controller as this.

MyApp .controller('MyController', ['$scope', 'ApiFactory',
  function ($scope, ApiFactory) {

    $scope.Users = null;

    ApiFactory.getUsers(count).then(function(data)
    {
      $scope.Users = data;
    });
 } 
 ]);
ssilas777
  • 9,672
  • 4
  • 45
  • 68
  • 1
    I would not pass $http promise to controller. I prefer to handle errors in the service (here ApiFactory) and then resolve promise to request result, returning data.data – b1r3k Aug 30 '13 at 10:04
  • what should say about call REST by $resource? – unknownbits Sep 01 '13 at 16:08
  • @b1r3k Wouldn't agree with handling response error in the service. For sure, catch the error but by passing the promise back to the controller, you offer the opportunity to surface a notification of the error to the user. To respond to the front-end from the factory would introduce tight coupling between the back-end and the front-end. – John Kelleher Sep 01 '14 at 20:14
  • Also, passing back the promise from the service allows you to chain API calls together in the controller, and have a single catch error handler. Not at all bad practise OMHO. Remains testable, separated, and neat. – dandanknight Jul 15 '15 at 19:09
2

You can use restangular https://github.com/mgonto/restangular

And you will call your api like that :

// Only stating main route
Restangular.all('accounts')

// Stating main object
Restangular.one('accounts', 1234)
Tib
  • 2,553
  • 1
  • 27
  • 46
1

As long as you use the $http service it doesnt really make any difference

Although there is the provider methodology which states that you should have a data provider in the client side as well as the server side

For this matter I suggest a factory which exposes the methods you want and is utilizing the $http service itself

Kia Panahi Rad
  • 1,235
  • 2
  • 11
  • 22
1

If your going to use that REST API call in more than one controller it is best to create a service that is injected as a dependency into the controllers that need it. Like already mentioned, you want to use $resource to handle RESTful APIs.

index.html:

<!-- Include Angular and angular-resources -->
<script src="angular.js"></script>
<script src="angular-resource.js"></script>

<!-- Set up your angular module -->
<div ng-app="RESTfulServiceExample">
    <div ng-controller="HomeController">
        <ul>
            <li ng-repeat="game in games">{{game.GameName}}</li>
        </ul>
    </div>
</div>

<script>
    // Inject angular-resource as ngResource into your module
    var gameListApp = angular.module('RESTfulServiceExample', ['ngResource']);

    // Create a service to call API which can be used by many controllers
    gameListApp.factory('GameService', ['$resource', function($resource) {
        return $resource('/game/:gameId', {gameId: '@id'});
    }]);

    // Create a controller that uses your service
    gameListApp.controller('HomeController', function($scope, GameService) {
        // GET: /game/
        var games = GameService.query();

        // Use response in HTML template
        $scope.games = games;
    });

    // Another controller could use the same service
    gameListApp.controller('GameController', function($scope, GameService) {
        // use GameService for another purpose
    });
</script>

Reference: AngularJS: $resource

Eric Wardell
  • 183
  • 2
  • 10