Consuming REST services with AngularJS

There are a lot of complicated examples out there on consuming REST services with AngularJS. If you're staring at a fully developed $resource object for the first time, it can be difficult to take in.

Let's step all the way back... What is a $resource? it's vaguely named, but if you just take the first 3 letters and add a "T", it will make a lot more sense.

It is an AngularJS resource, aka $resource or ngResource, "let's you interact with RESTful server-side data source."

In the examples below, I am using the angular-seed project as a starting point for the following code examples.

Before we move on...
Don't forget: You will need to include angular-resource.js if you are not using the fully minimized version of angularjs.

index.html

...
  <script src="lib/angular/angular.js"></script>
  <script src="lib/angular/angular-resource.js"></script>
...

And with that, let's create our first REST consumer service. In this example, we will create a ngResource which sends a GET request to the angular.js issue queue on GitHub. (https://api.github.com/repos/angular/angular.js/issues).

By default, the services.js file looks like this. (I moved the dot before value() to the next line so it will make sense when we add more)

js/services.js (default)

angular.module('myApp.services', [])
  .value('version', '0.1');

To add our first resource to this service, we need to inject ngResource and then add a factory to define our resource.

js/services.js (new)

angular.module('myApp.services', ['ngResource'])
  .factory('AngularIssues', function($resource){
    return $resource('https://api.github.com/repos/angular/angular.js/issues', {})
  })
  .value('version', '0.1');

That is all you need to consume a REST service that doesn't require any parameters.

Let's use MyCtrl1 in the seed project to fetch and display the issue data.

To use this service, we need to inject the resource (AngularIssues) and $scope. Then, just add the handler logic.

Pitfall: Understand, the result needs to be set inside the callback because resource requests are asynchronous.
$resource.get() vs $resource.query(): If the endpoint returns an array of object (like GitHub is doing), use .query(). i.e. AngularIssues.query() On the other hand, if it is not returning an array, use .get().

js/controllers.js

angular.module('myApp.controllers', []).
  controller('MyCtrl1', ['$scope', 'AngularIssues', function($scope, AngularIssues) {
    // Instantiate an object to store your scope data in (Best Practices)
    $scope.data = {};
   
    AngularIssues.query(function(response) {
      // Assign the response INSIDE the callback
      $scope.data.issues = response;
    });

  }])
  .controller('MyCtrl2', [function() {

  }]);
Side Note: Notice I instantiate $scope.data and then assign the issues to $scope.data.issues. If you're not sure why I did not just use $scope.issues, make it a point to look at Understanding Scopes and the best practices video.

This controller now will retrieve the AngularJS GitHub issues when #/view1 is loaded, and assign the resulting object to $scope.data.issues.

Now it's time for the fun part. Let's use ng-repeat to populate a table with the issue data.

partials/partial1.html

<h3>AngularJS GitHub Issues</h3>
<table class="table table-striped">
  <tr>
    <th>Number</th>
    <th>State</th>
    <th>Reporter</th>
    <th>Title</th>
    <th>Description</th>
  </tr>
  <tr ng-repeat="issue in data.issues">
    <td>{{issue.number}}</td>
    <td>{{issue.state}}</td>
    <td>{{issue.user.login}}</td>
    <td>{{issue.title}}</td>
    <td>{{issue.body}}</td>
  </tr>
</table>

If you run your app, you should now see a list of issues.

Note: If running the app locally, you will need to disable browser security. On Mac OS X, close Chrome completely and run this from the terminal:
open -a Google\ Chrome --args --disable-web-security

You will not have to worry about this if you are running it on a web server.

The code for this article has been pushed up to GitHub: https://github.com/mikemilano/angular-seed-rest

Here's a jsfiddle I based a talk on for our North County San Diego AngularJS meetup, that does not use angular-seed, but has a few more bells and whistles: http://jsfiddle.net/coder1/9TsdS/1/