Consuming REST APIs with Restangular

@mgonto

software developer

Aquicore Inc.

Learning Restangular

So Let's start

Let's create a WebApp with AngularJS

Enter your name

Hello {{person}}

<input type="text" ng-model="person" value="" />
<span>Hello {{person}} </span>

I'm sorry to tell you this is not an app

There's no real data

There's no information

We want a centralized point to access it

REST-MAN

AngularJS has $resource for this

Let's use it

Let's fetch an user

var User = $resource('/api/v1/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.name = 'Gonto';
  user.$save();
});

Let's now fetch his Cars

var Car = $resource('/api/v1/user/:userId/cars/:carId',
 {userId:123, carId:'@id'});
 
 var cars = Car.query(function() {
   var firstCar = cars[0];
   firstCar.name = "Honda Fit";
   firstCar.$save();
 });

Let's fetch an user

var User = $resource('/api/v1/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.name = 'Gonto';
  user.$save();
});

Let's now fetch his Cars

var Car = $resource('/api/v1/user/:userId/cars/:carId',
 {userId:123, carId:'@id'});
 
 var cars = Car.query(function() {
   var firstCar = cars[0];
   firstCar.name = "Honda Fit";
   firstCar.$save();
 });

Let's fetch an user

var User = $resource('/api/v1/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.name = 'Gonto';
  user.$save();
});

Let's now fetch his Cars

var Car = $resource('/api/v1/user/:userId/cars/:carId',
 {userId:123, carId:'@id'});
 
 var cars = Car.query(function() {
   var firstCar = cars[0];
   firstCar.name = "Honda Fit";
   firstCar.$save();
 });

Let's fetch an user

var User = $resource('/api/v1/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.name = 'Gonto';
  user.$save();
});

Let's now fetch his Cars

var Car = $resource('/api/v1/user/:userId/cars/:carId',
 {userId:123, carId:'@id'});
 
 var cars = Car.query(function() {
   var firstCar = cars[0];
   firstCar.name = "Honda Fit";
   firstCar.$save();
 });

Let's fetch an user

var User = $resource('/api/v1/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.name = 'Gonto';
  user.$save();
});

Let's now fetch his Cars

var Car = $resource('/api/v1/user/:userId/cars/:carId',
 {userId:123, carId:'@id'});
 
 var cars = Car.query(function() {
   var firstCar = cars[0];
   firstCar.name = "Honda Fit";
   firstCar.$save();
 });

We need to create one Resource object per entity

It doesn't handle relationship between data

It doesn't handle nested RESTFul Resources

We can't use element's own href

We can't add configurations per resource agroupation

Not cool

Restangular-Signal

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();
  cars.post({name: 'New Model Extra Cool'});
});

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();
  cars.post({name: 'New Model Extra Cool'});
});

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();
  cars.post({name: 'New Model Extra Cool'});
});

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();
  cars.post({name: 'New Model Extra Cool'});
});

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();  
  cars.post({name: 'New Model Extra Cool'});
});

First we configure it

RestangularProvider.setBaseUrl('/api/v1')

Let's fetch an user

Restangular.one('user', 123).get().then(function(user) {
  $scope.user = user;
  user.name = 'Gonto';
  user.put();
});

Let's now fetch his Cars

$scope.user.getList('cars').then(function(cars) {
  var firstCar = cars[0];
  firstCar.name = "Honda Fit";
  firstCar.put();  
  cars.post({name: 'New Model Extra Cool'});
});

You can navigate your hierarchies using all and one

Restangular.all('users').one('car', 123).get();
Restangular.allUrl('users', 'http://example.com/users').all('messages').getList();
Restangular.one('users', 123).all('cars').getList();
$scope.user.all('cars').getList();

What if the element has a link to self?

First we configure it

RestangularProvider.setRestangularFields({
  selfLink: 'self.href'
})

Let's fetch all users

Restangular.all('users').getList().then(function(users) {
  // user.self.href = 'http://example.com/users/gonto'
  // This triggers delete to that URL
  users[0].remove()
});

How about adding my own methods and properties?

Let's add the methods

Restangular.addElementTransformer('users', false, function(user) {
  user.addRestangularMethod('ping', 'post', 'do-ping', {'X-App': 'Example'});
  return user;
})

// OR

Restangular.extendModel('users', function(user) {
  user.addRestangularMethod('ping', 'post', 'do-ping', {'X-App': 'Example'});
  return user;
});

Let's use it

Restangular.allUrl('users').getList().then(function(users) {
  users[0].ping();
  users[0].customPUT({message: 'Hey John'}, 'update-message');
});

Can we configure this further?

Restangular.setRestangularFields({
  id: '_id.$oid'
});

Restangular.setResponseInterceptor(function(data, operation, what) {
  stopLoading();
  if (operation == 'getList') {
    return data[what];
  }
  return data;
});

Restangular.setRequestInterceptor(function(elem) {
  startLoading();
  delete elem.extraInfo;
  return elem;
});

Restangular.setMethodOverriders(['put', 'delete']);

Restangular.setRequestSuffix('.json');

Restangular.setErrorInterceptor(function(response) {
  stopLoading();
  displayError();
});

Scoped configurations

var BondRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  RestangularConfigurer.setDefaultHeaders({'X-Auth': 'James Bond'})
});

BondRestangular.one('place', 12).get();

It uses ETags by default. You don't have to worry about this

It's entirely based on promises

It supports all HTTP methods including Patch, Trace, etc.

You can run custom operations

And more

Thank you for listening

Questions?

Consuming REST APIs with Restangular

@mgonto