
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 <space> to select, <a> to toggle all, <i> 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 <space> to select, <a> to toggle all, <i> 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 <space> to select, <a> to toggle all, <i> to inverse selection)
◉ local
◯ bitbucket
◯ dropbox
❯◯ facebook
◯ github
◯ googles</spoiler>tagram
И секунд за 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!
Автор: Kickidler