NgResource

CRUD without boilerplate

Objectives

  • Replace RESTful $http requests with ng-resource
     

  • Appreciate the power of the REST standard

Refresher - Whats REST?

  • "Representational State Transfer"
     
  • Maps actions to HTTP verbs (GET, POST, PUT, PATCH, DELETE)
     
  • Standard URL design
     
  • Client/Server && "Separation of Concerns"
     
  • Ultimately, REST is a design pattern.  When we follow a shared design, we can use shared tools.

Verbs, URLS, and REST

URLs follow a pattern: host/api-base/{collection}/{id}

collections and individual items behave differently:

$http + REST

getTodos: function(){
  return $http.get("/api/todos"); // get whole collection
},
createTodo: function(todo){
  return $http.post("/api/todos", todo); // create new todo
},
getTodo: function(id){
  return $http.get("/api/todos/" + id); // get single todo
},
editTodo: function(id,todo){
  return $http.put("/api/todos/" + id, todo); // update single todo
},
deleteTodo: function(id){
  return $http.delete("/api/todos/" + id); // delete single todo
}

For example, if I were using $http and my database had a table called todo:

$resource + REST

angular.module("todoApp", ['ngRoute','ngResource']);

// ...
angular.module("todoApp").controller($scope, $resource) {
    var todoResource = $resource('/api/todos/:id', { id: '@id' });
}

Because we are allowed to assume the server code is REST compliant, here is the same featureset with $resource

Booyah.

$resource


$resource('/api/todos/:id', { id: '@id' });

So, whats happening here?

Resource URL on our API

URL parameter, filled out based on the object passed to my resource

When prefixed with @: The name of the property which will be mapped into the :id url field.
This can also be a static value.

$resource + REST

var todoResource = $resource('/api/todos/:id', { id: '@id' });

// envoking a $resource returns an object. 
var myTodo = todoResource.get({id: 1}, function(todo) {
    console.log(todo === myTodo) // true
    
    // You can use the object in cool ways:
    myTodo.newProperty = "Bang, new prop!";

    // POST myTodo JSON to /api/todos/1
    // This one isnt quite right...
    myTodo.$save(); 

    // DELETE resourceTodo JSON to /api/todos/1
    myTodo.$delete(); 
});

var arbitraryFrontEndTodo = {task: "DO ALL THE THINGS"};
todoResource.save(arbitraryFrontEndTodo) // POST arbitraryFrontEndTodo JSON to /api/todos

So how do I use it?

Getting to PUT

    // POST resourceTodo JSON to /api/todos/1
    // This one isnt quite right...
    resourceTodo.$save(); 

    // This POSTS to /api/todos which is correct
    // We also let the DB decide what id this new obj should get
    var arbitraryFrontEndTodo = {task: "DO ALL THE THINGS"};
    todoResource.$save(arbitraryFrontEndTodo) // POST the todo JSON to /api/todos

Recall from four slides ago, to save an individual resource that has an id already we're supposed to use PUT.

Getting to PUT

var todoResource = $resource('/api/todos/:id', { id: '@id' }, {
   update: {
     method: 'PUT' // this method issues a PUT request
   }
 });

var myTodo = todoResource.get({id: 1}, function(todo) {
    console.log(todo === resourceTodo) // true
    
    // You can use the object in cool ways:
    myTodo.newProperty = "Bang, new prop!";

    // PUT resourceTodo JSON to /api/todos/1
    myTodo.$update(); 
}

All we have to do is give an additional method when we construct the resource

Questions?

Made with Slides.com