RESTful endpoints often expose CRUD operations that are accessible by calling different HTTP methods on a set of similar URLs. The code that interacts witch such endpoints is usually straightforward but tedious to write. The $resource
service allows us to eliminate the repetitive code. We can also start to operate on a higher abstraction level and think of data manipulation in terms of objects (resources) and method calls instead of low-level HTTP calls.
Note
The $resource
service is distributed in a separate file (angular-resource.js
), and resides in a dedicated module (ngResource
). To take advantage of the $resource
service we need to include the angular-resource.js
file and declare dependency on the ngResource
module from our application’s module.
To see how easy is to interact with the RESTful endpoint using the $resource
service we are going to construct an abstraction over the collection of users exposed as a RESTfulservice by the MongoLab:
angular.module('resource', ['ngResource']) .factory('Users', function ($resource) { return $resource('https://api.mongolab.com/api/1/databases/ascrum/ collections/users/:id', { apiKey:'4fb51e55e4b02e56a67b0b66', id:'@_id.$oid' }); })
We start by registering a recipe (a factory) for the User
constructor function. But notice that we don’t need to write any code for this constructor function. It is the $resource
service that will prepare implementation for us.
The $resource
service will generate a set of methods that make it easy to interact with a RESTFul endpoint. For example, querying for all the users in the persistence store is as simple as writing:
.controller('ResourceCtrl', function($scope, Users){ $scope.users = Users.query(); });
What will happen upon the call to the User.query()
method is that $resource
generated code is going to prepare and issue an $http
call. When a response is ready the incoming JSON string will get converted to a JavaScript array where each element of this array is of type Users
.
Note
Calls to the $resource
service return a generated constructor function augmented with methods to interact with a RESTful endpoint: query
, get
, save
and delete
.
angularjs requires very little information to generate a fully functional resource. Let’s examine the parameters of the $resource
method to see what input is required and what can be customized:
$resource('https://api.mongolab.com/api/1/databases/ascrum/collections/users/:id', { apiKey:'4fb51e55e4b02e56a67b0b66', id:'@_id.$oid' });
The first argument is a URL or rather a URL pattern. The URL pattern can contain named placeholders starting with the colon character. We can specify only one URL pattern which means that all HTTP verbs should use very similar URLs.
Tip
If your back-end uses a port number as part of the URL, the port number needs to be escaped while supplying the URL pattern to the $resource
call (For example, http://example.com\\:3000/api
). This is required since a colon has a special meaning in the $resource
‘s URL pattern.
The second argument to the $resource
function allows us to define default parameters that should be sent with each request. Please note that here by “parameters” we mean both placeholders in a URL template, and standard request parameters sent as a query string. angularjs will try first to “fill holes” in the URL template, and then will add remaining parameters to the URL’s query string.
The default parameters can be either static (specified in a factory) or dynamic, taken from a resource object. Dynamic parameter values are prefixed with a @
character.
Constructor-level and instance-level methods
The $resource
service automatically generates two sets of convenience methods. One set of methods will be generated on the constructor-level (class-level) for a given resource. The aim of those methods is to operate on collections of resources or cater for the situation where we don’t have any resource instance created. The other set of methods will be available on an instance of a particular resource. Those instance-level methods are responsible for interacting with one resource (one record in a data store).
Constructor-level methods
The constructor function generated by the $resource
has a set of methods corresponding to different HTTP verbs:
Users.query(params, successcb, errorcb)
: It issues an HTTP GET request and expects an array in the JSON response. It is used to retrieve a collection of items.Users.get(params, successcb, errorcb)
: It issues an HTTP GET request and expects an object in the JSON response. It is used to retrieve a single item.Users.save(params, payloadData, successcb, errorcb)
: It issues an HTTP POST request with request body generated from the payload.Users.delete(params,successcb, errorcb)
(and its alias:Users.remove
): It issues an HTTP DELETE request.
For all the methods listed earlier the successcb
and errorcb
denote a success and error callback functions, respectively. The params
argument allows us to specify per-action parameters that are going to end up either as part of the URL or as a parameter in a query string. Lastly, the payloadData
argument allows us to specify the HTTP request body where appropriate (POST and PUT requests).
Deven Rathore
I'm Deven Rathore, a multidisciplinary & self-taught designer with 3 years of experience. I'm passionate about technology, music, coffee, traveling and everything visually stimulating. Constantly learning and experiencing new things.
Comments