Categories
Javascript

REST access in AngularJS using ngResource

This will be a short and quick walk through on how to make REST API calls using AngularJS. We shall use ngResource to aid us.

Loading ngResource

If we want to use the ngResource module, we have to make sure it’s being loaded separately along with angular. We need to have something like –

<script src="/static/js/angular.min.js" type="text/javascript"></script>
<script src="/static/js/angular-resource.min.js" type="text/javascript"></script>

Creating a Module and Resource Objects (Mapping)

Now, we shall create a module named “apiService” to keep our REST stuff separate from our main application logic.

var service = angular.module("apiService", ["ngResource"]);

Then we shall map REST api calls to our Angular resource objects. Here we create a Booking resource object and the factory method allows us to do that –

// Booking Resource
service.factory("Booking", function ($resource) {
    return $resource(
        "/api/booking/:Id",
        {Id: "@Id" },
        {
            "update": {method: "PUT"},
            "reviews": {'method': 'GET', 'params': {'reviews_only': "true"}, isArray: true}

        }
    );
});

Here we create a new resource object which maps to the API url – “/api/booking” with an optional parameter “Id”. Then we define a set of default parameters to be used, here we instruct to extract the value of “:Id” if “Id” is present in the set of params passed.

The above resource object can make these requests:

GET /api/booking/ — Gets all booking
GET /api/booking/1 — Gets the booking with ID 1
POST /api/booking/ — Creates a new booking
PUT /api/booking/1 — Update booking ID 1
DELETE /api/booking/1 — Delete booking ID 1

Besides the basic methods, we have also added a custom method named “reviews” which would add “reviews_only=true” to make a GET query and return the result as an array. This is helpful to deal with custom queries.

Making Rest Calls

Here comes the fun, how do we use the Booking object to make the different calls?

// Get all booking returned by the API
var bookings = Booking.query(); // Calls: GET /api/booking/

// Get Booking ID 1
var booking = Booking.get({},{'Id': 1}); // Calls: GET /api/booking/1

// Change a value
booking.fees = 34;

// Save the changes (update it)
booking.$save(); // Calls: PUT /api/booking/1

// Delete Booking ID 1
Booking.delete({}, {'Id': 1}); // Calls: DELETE /api/booking/1

// Get Reviews
var reviews = Booking.reviews(); // Calls: GET /api/booking/?reviews_only=true

When making the calls, we need to remember that the first parameter contains the actual data. These data will be used as the parameters of the API. This can be appended like query strings or POSTed. The API will use these data to filter the response. Where as the second parameter overrides the default parameters for the resource definition. It is used by Angular to decide how to make the REST call. In our case, we used – “/api/booking/:Id” as our api entry point and then defined default parameters as – {Id: “@Id” }. So here, the second parameter will help angular decide which URL (by providing the value for Id) to make the request to. We didn’t need to pass any data but we did need to pass the ID in some methods. This is why most of the methods were passed an empty object as the first parameter.

This should explain things a bit more –

// URL: /api/booking?name=masnun
Booking.query({'name':'masnun'});

// URL: /api/booking/1
Booking.query({},{'Id':1});

// URL: /api/booking/1?name=masnun
Booking.query({'name':'masnun'},{'Id':1});

Each of these methods allow a callback function to be executed when there is a response from server.

 
Booking.delete({}, {'Id': 1}, function () {
    console.log("Deleted");
});

Simple, isn’t it?

20 replies on “REST access in AngularJS using ngResource”

The AngularJS documentation is pretty clear on saying that “$save” will use “POST” instead of “PUT”.  I’ve found several blogs that wonder why the heck they did that and provide options of either defining the custom “update” function, or defining a custom Resource service that uses ngResource, but modifies the prototype to have “$save” use PUT instead of POST.

You haven’t included an example of a controller that takes advantage of the service.  Could you add one?  I’ve followed your code and added my own controller that calls the service using the methods you provide.  But when I try to load the angular code I get the following error:

Unknown provider: $resourceProvider <- $resource at Error (native)

one thing that I don’t quite understand:

var bookings = Booking.query();

Booking.query() method will have to fetch the response through a get call. That means that this call would be async and the result will be fetch on the success http get event isn’t it? As javascript doesn’t wait for method to execute how is that supposed to work? I’m not javascript pro so I’m just trying to learn the details

thanks 🙂

From the docs :

It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.

might help?? 🙂

Yeah, I wrote it like that to demonstrate how the parameters map to the URL scheme defined for making requests.

For single objects, Booking.get() is the way to go.

I had the same Problem.
Solution was to reference $resource (in this case “apiService” as dependency of your app. E.g in your app.js:

angular.module( 'myApp', ['ngResource', 'apiService']);

And in your controller:

angular.module( 'mySubApp', []).controller( 'myController', ['$scope', 'Booking', function myController($scope, $booking) {
$scope.bookings = $booking.query();
}]);

How would you make a query like this using $resource?

db.locations.find({latitude: {$gt: 33.962, $lt: 33.966}, longitude: {$gt: -84.447, $lt: -84.443}})

 

Thanks

Hi,

 

why you didin show us the Post method call in the above example????????

 

And one more thing..

 

I have one requirement in my project where i need to send a login credentials to the user and it should return some object in that request..

 

I should not go for the get method because it displays the user credentials in the url…how can i achieve it.

Just wanted to say this was so extremely helpful in general.  And also I couldn’t figure out how to send the query string and parameters via a query() in a factory, now I understand. Thanks!

Using $resource, is there a way to execute an unbound action, one that uses a NonBindableAction attribute in WCF Data Services?

Comments are closed.