Как подключить Angular.js к API бакенду

Illustration of a person sitting on the floor while leaning against a wall and looking at a tablet, with a spotlight effect highlighting them. Illustration of a person sitting on the floor while leaning against a wall and looking at a tablet, with a spotlight effect highlighting them.

В этой статье мы научимся соединять наше приложение с простым API при помощи библиотеки Restangular. Restangular – это популярная альтернатива встроенной в сам Angular.js библиотеки для работы с REST API. О её преимуществах над стандартной библиотекой хорошо рассказано на странице проекта на github: https://github.com/mgonto/restangular. Например, она поддерживает все HTTP методы и лишена различных неприятных багов встроенной в Angular.js библиотеки.

В качестве API мы будем использовать небольшое веб-приложение, написанное на фреймворке Sinatra, который написан на Ruby. Вам не нужно писать ruby код. Чтобы запустить API на вашей машине нужно выполнить следующие действия:

  1. Установите Ruby если у вас его ещё нет. В сети множество руководств на эту тему, в том числе на официальном сайте https://www.ruby-lang.org/en/
  2. Скачайте приложение git clone https://github.com/mkdev-me/sinatra-api-example
  3. Зайдите в папку с приложением и выполните команду bundle install
  4. После этого выполните rake db:create db:migrate
  5. И, наконец, запустите приложение командой ruby app.rb

Готово! Ваш маленький бакэнд готов к работе по адресу localhost:4567. Теперь мы можем обновить Angular.js приложение для работы с API.

Мы уже подключили Restangular на этапе настройки нашего приложения: вы можете увидеть его в списке зависимостей в файле bower.json. Более того, библиотека уже загружена как модуль, обратите внимание на эту строчку в src/app/index.js:

angular.module('ngmkdev', ['restangular', 'ui.router', 'ui.bootstrap'])

Поэтому мы можем перейти сразу к коду. В первую очередь нам необходимо задать базовый URL, используя который Restangular будет строить остальные ссылки. Для этого в библиотеке есть провайдер RestangularProvider, который мы можем использовать в блоке config в src/app/index.js:

// src/app/index.js
angular.module('ngmkdev', ['restangular', 'ui.router'])
  .config(function ($stateProvider, $urlRouterProvider, RestangularProvider) {

    RestangularProvider.setBaseUrl("http://localhost:4567");
    <  >
});

Основной ссылкой по-умолчанию будет ссылка на сервер с нашим API. Теперь обновим TransactionsStore так, чтобы он использовал данные с сервера. Добавим два новых метода: loadTransactions загрузит все данные с сервера, а addTransaction добавит новую транзакцию.

// src/components/transations_store.serve.js
angular.module('ngmkdev').factory('TransactionsStore', function(Restangular) {
  return {
    transactions: [],
    loadTransactions: function() {
      this.transactions = Restangular.all('transactions').getList().$object;
    },
    addTransaction: function(transaction) {
      var that = this;
      return Restangular.all('transactions').post({transaction: transaction}).then(function() {
        that.transactions.push(transaction);
      })
    },
    sum: function() {
      var sum = 0;
      this.transactions.forEach(function(el) {
        sum += parseFloat(el.amount);
      })
      return sum;
    }
  }
});

Обратите внимание на функцию then(). Она выполняется только тогда, когда завершился запрос на добавление транзакции. Подобный механизм называется promises, который является альтернативой привычному по jQuery механизму коллбеков. Отличие promise в том, что нам не нужно держать в памяти когда какой коллбек выполнится. Angular.js таким образом предоставляет гарантию, что если функция A завершила своё выполнение, то функция B выполнится (и только тогда, когда функция А действительно успешно выполнится).

В данном случае мы гарантируем, что массив транзакций обновится только после успешного сохранения новой транзакции на сервере. Чтобы сократить число запросов к серверу мы будем держать в памяти все транзакции и обновлять этот массив вручную, вместо того чтобы каждый раз получать все транзакции с сервера.

Большинство функций Restangular возвращают promise-объекты. Например, getList(), который мы используем для получения всех транзакций. Чтобы получить сами транзакции мы можем либо использовать then(), либо метод $object, который сразу вернёт нам все транзакции.

При помощи метода all() мы указываем с каким ресурсом работаем. Restangular сам догадывается, по каким ссылкам получать и отправлять данные, при условии что ваше API приложение соответствует REST стандартам. Таким образом, post() создаст новую запись, get() получит запись и т.п.

Код контроллера не претерпел больших изменений:

// src/app/main/transactions.controller.js
angular.module('ngmkdev').controller('TransactionsCtrl', function($scope, TransactionsStore) {

  TransactionsStore.loadTransactions();

  this.addTransaction = function() {
    TransactionsStore.addTransaction(this.newTransaction);
    this.resetTransaction();
  }

  this.resetTransaction = function() {
    this.newTransaction = {
      amount: 0.0,
      date: "1993-02-01",
      description: null
    }
  }
  this.transactions = TransactionsStore.transactions;
  this.resetTransaction();
});

Теперь все новые транзакции будут сохранены в базе данных и после перезагрузки страницы они никуда не пропадут.

Вы наверняка создали множество тестовых транзакций, чтобы посмотреть как всё работает. Теперь надо бы от них как нибудь избавиться. Коммит с изменениями: a0629f.

Домашняя работа:

  1. Добавьте и реализуйте кнопку удаления транзакции.


Это последняя статья курса по Angular.js. За 6 выпусков мы познакомились со всеми основными инструментами современной фронтенд разработки и, следуя лучшим практикам, написали полноценное приложение, работающее с бакендом через API. Полученные знания послужат отличным фундаментом для написания более сложных приложений на Angular.js. Пишите в комментариях что думаете об этой серии статей и как проходит ваше изучение и применение Angular.js.