Как подключить Angular.js к API бакенду
В этой статье мы научимся соединять наше приложение с простым API при помощи библиотеки Restangular. Restangular – это популярная альтернатива встроенной в сам Angular.js библиотеки для работы с REST API. О её преимуществах над стандартной библиотекой хорошо рассказано на странице проекта на github: https://github.com/mgonto/restangular. Например, она поддерживает все HTTP методы и лишена различных неприятных багов встроенной в Angular.js библиотеки.
В качестве API мы будем использовать небольшое веб-приложение, написанное на фреймворке Sinatra, который написан на Ruby. Вам не нужно писать ruby код. Чтобы запустить API на вашей машине нужно выполнить следующие действия:
- Установите Ruby если у вас его ещё нет. В сети множество руководств на эту тему, в том числе на официальном сайте https://www.ruby-lang.org/en/
- Скачайте приложение
git clone https://github.com/mkdev-me/sinatra-api-example
- Зайдите в папку с приложением и выполните команду
bundle install
- После этого выполните
rake db:create db:migrate
- И, наконец, запустите приложение командой
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.
Домашняя работа:
- Добавьте и реализуйте кнопку удаления транзакции.
Это последняя статья курса по Angular.js. За 6 выпусков мы познакомились со всеми основными инструментами современной фронтенд разработки и, следуя лучшим практикам, написали полноценное приложение, работающее с бакендом через API. Полученные знания послужат отличным фундаментом для написания более сложных приложений на Angular.js. Пишите в комментариях что думаете об этой серии статей и как проходит ваше изучение и применение Angular.js.