Feathers JS — как создать backend для своего приложения всего за 5 минут
Feathers — мало известный (увы!), но при этом очень мощный и удобный фреймворк для создания серверных приложений на Node.js. В его основе лежит гораздо более популярная технология Express.
Но если Express в основном ориентирована на создание web-приложений и генерацию html-кода с использованием различных шаблонизаторов, то Feathers предназначен для создания сервисов (REST, Socket.io и Primus). При этом от разработчика требуется минимум усилий и доработки кода — ведь всё уже написано до нас.
При всей мощи Feathers, пишут о нём крайне мало. Последняя публикация на Хабре о нём была в 2013 году, никаких книг статей и курсов не существует. Сам я наткнулся на него совершенно случайно, когда искал наиболее удобный вариант написания сервера для создающейся сейчас системы персональной эффективности.
От такой несправедливости мне стало горько и я решил написать этот текст о том, как с помощью Feathers за жалкие 5 минут создать действительно работающий сервер, предоставляющий сервисы для того же React.
Итак, включаем секундомер? Нет, чуть позже. Сейчас разберемся с теорией.
В Feathers есть несколько типов объектов:
- middleware — то есть промежуточные обработчики, которые функционируют так же, как и в Express, а значит для нашего рассказа не интересны;
- сервисы — обработчики, которые исполняются на сервере, а данные передают клиента. Для вызова сервисов используются три технологии — REST, Socket.io и Primus. Причем разработчику нет нужды самостоятельно реализовывать передачу данных. Он просто реализует несколько предопределенных методов (find, get, create, update, patch, remove, setup), а обо всем остальном позаботится фреймворк;
- хуки — процедуры, которые автоматически вызываются до и после работы сервисов. Они позволяют проверить/исправить запрос, передаваемый сервису, и изменить данные, возвращаемые клиенту. Хуки можно писать самому, но есть стандартные хуки (например, отрезающие одну колонку из возвращаемого набора данных).
Вот теперь можно и начать работу.
Первым делом устанавливаем пакет feathers-cli:
$ npm install -g feathers-cli
Дальше нужно создать каталог для приложения и перейти в него:
$ mkdir feathers-app
$ cd feathers-app/
Теперь генерируем скелет приложения:
$ feathers generate
Вначале зададим имя и описание для нового приложения, а потом выберем какие API для доступа к нему мы хотим использовать»:
? Project name TestApp
? Description Приложение для быстрой демонстрации возможностей Feathers
? What type of API are you making? (Press to select, to toggle all, to inverse selection)
❯◉ REST
◉ Realtime via Socket.io
◯ Realtime via Primus
Затем нужно определиться будем ли мы разрешать CORS (Cross-Origin Resource Sharing) и если да, то для каких доменов:
? Project name TestApp
? Description Приложение для быстрой демонстрации возможностей Feathers
? What type of API are you making? REST, Realtime via Socket.io
? CORS configuration (Use arrow keys)
❯ Enabled for all domains
Enabled for whitelisted domains
Disabled
Теперь пришла пора выбрать основной тип базы данных. Если у вас их несколько, не волнуйтесь, для каждого конкретного сервиса вы сможете указывать альтернативные типы БД:
? Project name TeatApp
? Description Приложение для быстрой демонстрации возможностей Feathers
? What type of API are you making? (Press to select, to toggle all, to inverse selection)REST, Realtime via Socket.io
? CORS configuration Enabled for all domains
? What database do you primarily want to use? (Use arrow keys)
Memory
MongoDB
MySQL
MariaDB
❯ NeDB
PostgreSQL
SQLite
SQL Server
I will choose my own
Если вы не собираетесь допускать к своему backend всех подряд, то пора подумать об аутентификации. Провайдера можно написать своего или выбрать готового из списка (на самом деле провайдеров аутентификации больше, чем показано, поэтому стоит прокрутить список в поисках нужного):
? Project name TestApp
? Description Приложение для быстрой демонстрации возможностей Feathers
? What type of API are you making? REST, Realtime via Socket.io
? CORS configuration Enabled for all domains
? What database do you primarily want to use? NeDB
? What authentication providers would you like to support? (Press to select, to toggle all, to inverse selection)
◉ local
◯ bitbucket
◯ dropbox
❯◯ facebook
◯ github
◯ googlestagram
И секунд за 10 генератор создаст для нас все необходимые файлы + автоматически загрузит npm пакеты.
Структура каталогов исходного кода следующая:
- config — конфигурационные файлы, описывающие параметры приложения (домен, порт, ключ аутентификации и т.п). default.json используется на этапе разработки, а production.json — в продакшене
- public — этот каталог был напрямую унаследован от Express. Сюда помещаются все статические ресурсы (картинки, html-файлы), которые должны быть переданы в браузер клиента
- test — код для тестирования backend
- source/service — тут будут храниться «сердца» нашего приложения — сервисы, по одному на подкаталог
- source/hooks — глобальные хуки, которые будут применяться ко всем сервисам
- source/middleware — обычное middleware Express, например логи
- source/app.js — основной файл приложения, который подключает сервисы, middleware, хуки, статические ресурсы и прочее. Обычно ручное изменение не требуется
- source/index.js — просто импорт и старт app.js. В большинство случаев трогать этот файл нет смысла, но если вы пишете, например приложение Electron, то изменения вносите именно сюда
Формально приложение готово. Его даже можно запустить с помощью npm start. Из появившейся надписи мы узнаем, что сервер запущен по адресу localhost:3030. Зайдем на этот адрес — увидим пустую страничку с логотипом. Всё.
Дело в том, что мы пока что не создали ни одного сервиса. К счастью, сгенерировать не сложнее приложения.
Вводим в консоли:
$ feathers generate service
Задаем название сервиса (я выбрал contacts — для списка контактов) и выбираем откуда найдитесь сервис будет получать данные:
? What do you want to call your service? contacts
? What type of service do you need? (Use arrow keys)
generic
❯ database
В принципе можно выбрать вариант generic и самостоятельно реализовать с помощью методов сервиса (find, get, create, update, patch, remove, setup) процесс чтения/записи в базу данных. Но зачем? Ведь Feathers готов всё сделать за нас…
Итак, мы выбрали работу с базой, а в качестве базы указали уже привычный NeDB. На вопрос об аутентификации пока ответим отрицательно. Не потому что она не нужна вообще, просто обсудим её позже.
? What do you want to call your service? contacts
? What type of service do you need? database
? For which database? NeDB
? Does your service require users to be authenticated? (y/N)
В результате получаем сообщение о создании трёх файлов:
create src/services/contacts/index.js
create src/services/contacts/hooks/index.js
create test/services/contacts/index.test.js
Первый — собственно сама реализация сервиса, второй — его хуки, третий — код для тестирования работы сервиса.
Вот теперь можно с помощью npm start запустить приложение и посмотреть как оно работает. Вводим в консоли команду
$ curl 'http://localhost:3030/contacts/' -H 'Content-Type: application/json' --data-binary '{ "first_name": "John", "last_name":"Smith", "email":"jsmith@mail.emall"}'
и видим что у нас появился каталог /data (как и было задано в файле конфигурации), в нем создался файл contacts.db, а его содержимое — информация о Джоне Смите.
То есть мы получили вполне работающее приложение, не написав ни единой строчки кода!
И уложились в 5 минут.
Но это плюсы, а ведь как всегда есть и минусы:
- сервис не позволяет валидировать передаваемые ему для сохранения данные
- сервис возвращает данные в исходном виде, без какого-либо преобразования
Всё так. Но эти недостатки легко исправляются с помощью хуков. И во второй части мы потратим еще минут 15, чтобы превратить наш базовый сервер в весьма продвинутый.
…To be continued!
Комментарии (6)
20 февраля 2017 в 16:43
0↑
↓
То есть мы получили вполне работающее приложение, не написав ни единой строчки кода!
Зато мы нагенерировали немало кода. Но если в своем написаном коде я понимаю, что к чему, то в сгенерированной версии еще предстоит разобраться
20 февраля 2017 в 16:47
+1↑
↓
Этот код очень лаконичный. И очень хорошо структурированный.
Если коллегам будет интересно, могу запланировать третью часть, в которой опишу структуру сгенеренного кода.20 февраля 2017 в 17:14
0↑
↓
А можно пример?
20 февраля 2017 в 17:35
0↑
↓
Вот код нашего сервиса:'use strict'; const contacts = require('./contacts'); const authentication = require('./authentication'); const user = require('./user'); module.exports = function() { const app = this; app.configure(authentication); app.configure(user); app.configure(contacts); };
А вот — файла app.js:
'use strict'; const path = require('path'); const serveStatic = require('feathers').static; const favicon = require('serve-favicon'); const compress = require('compression'); const cors = require('cors'); const feathers = require('feathers'); const configuration = require('feathers-configuration'); const hooks = require('feathers-hooks'); const rest = require('feathers-rest'); const bodyParser = require('body-parser'); const socketio = require('feathers-socketio'); const middleware = require('./middleware'); const services = require('./services'); const app = feathers(); app.configure(configuration(path.join(__dirname, '..'))); app.use(compress()) .options('*', cors()) .use(cors()) .use(favicon( path.join(app.get('public'), 'favicon.ico') )) .use('/', serveStatic( app.get('public') )) .use(bodyParser.json()) .use(bodyParser.urlencoded({ extended: true })) .configure(hooks()) .configure(rest()) .configure(socketio()) .configure(services) .configure(middleware); module.exports = app;
Мне кажется, тут всё очень просто
20 февраля 2017 в 18:33
0↑
↓
Во всяких hello world примерчиках, код всегда лаконичный и структурированный. А если сравнить сгенерированный код Feathers JS, с кодом который генерирует LoopBack 3.0, то не такой уж он и структурированный.
20 февраля 2017 в 18:37
0↑
↓
Для всякого CRUD типа админок, да и просто быстро набросать основу — очень прикольно. Давайте продолжение!