Вместо введения

Раньше казалось, что быстро построить API для проекта средней сложности на NodeJS - довольно хлопотное дело. А если еще надо прикрутить валидацию данных, права на доступ к запросам, написать тесты этого API, то это вообще дело долгое и нетривиальное. Я намерен развеять этот миф. Используя один фреймворк, можно достаточно быстро построить качественное APIна NodeJS. Возможно, в этом руководстве Вам покажется реализуемое API очень простым - так оно и есть. Нужно учитывать, что это всего лишь пример! Вы всегда можете его масштабировать в рамках своего проекта. Итак, поехали!

Дорогу Loopback

Для построения API я выбрал достаточно интересный фреймворк Loopback. Давайте взглянем на его в действии!

Для начала нам необходимо установить консольную утилиту, которая идет в его поставке. Для это выполним команду:

npm i -g loopback-cli

После этого в папке с проектами создадим папку нашего нового проекта и перейдем в нее:

mkdir blog-api
cd ./blog-api

Теперь нам надо запустить установщик приложения:

lb

Далее нам будет предложено ответить на ряд вопросов:

  • Ввести название приложения - можно оставить предложенное.
  • Выбрать версию фреймворка - советую выбрать ветку 3x, она является текущей и уже довольна стабильна.
  • Выбрать тип приложения, файлы которого будут установлены - выбираем api-server.

Все, наш фреймворк начал работу, он скачает нужные файлы и установит с помощью npm требуемые зависимости. Наше API готово!

Ну или почти готово... =)

Давайте запустим наш сервер и взглянем на наш проект:

node ./server/server.js

Заходим по ссылкам в браузере:

1. localhost:3000

2. localhost:3000/explorer

Первая ссылка ведет в корень нашего API и выдает время запуска сервера и время его работы. Само же API будет доступно с префиксом /api. А вот вторая ссылка уже показывает, какие нам доступны вызовы API по моделям. Давайте создадим несколько и взглянем на результат.

А что же мы будем делать?

Небольшое лирическое отступление по поводу того, какое API мы собираемся сделать. Предлагается построить API блога. У нас будет две таблицы:

1. Blogs

  • id_blog - integer (pk)
  • title - string (required)
  • description - string

2. Article

  • id_article - inteegr (pk)
  • title - string (required)
  • body - string (required)

Первая таблица - блоги, а вторая таблица - статьи, относящиеся к блогам. Таблицы связаны внешним ключом отношением один ко многим. Вот такое простое API и будем строить, основанное всего на двух таблицах.

Модели - наше все!

Начнем с построения моделей приложения. Для этого в консоли набираем команду:

lb model

и следуем инструкциям утилиты. А она нас попросит ввести:

  • Название модели - вводим Blog.
  • Выбрать хранилище нашей модели - пока выбираем db (memory).
  • Выбрать тип модели - для наших нужд необходимо PersistedModel.
  • Будем ли мы использовать модель по rest - Да.
  • Собственное название модели множественного числа - пропускаем (пусть делает автоматически).
  • Куда поместить модель - выбираем common.

После этого необходимо указать какие поля создаем в модели. Там, в принципе, все просто: выбираем название, тип, обязательность поля и значение по умолчанию. Создаем модель Article аналогичным образом. После того как мы сделали эти две модели, для выхода из утилиты просто нажимаем enter. Файлы всех созданных моделей попадают в папку common/models с соответствующими названиями в виде двух файлов, например: blog.js + blog.json. В *.json файлах описаны настройки моделей: от кого наследуются, правила валидации, методы, свойства. В *.js файлах описываются различные асинхронные валидации, методы модели. К какому источнику данных (к какой БД) подключена модель, описываемая в файле server/model-config.json.

На текущий момент у нас должна быть следующая структура проекта:

Создав 2 модели Blog и Article можно взглянуть на их появление. Видим, что кроме модели User, появились еще две модели Blog и Article. Тут же для каждой модели представлены различные API, которые мы можем выполнить и получить результат ответа сервера. Давайте создадим три блога методом POST

Для этого раскрываем вкладку POST /BLOGS, нажимаем на поле Example value и в поле data появляются значения, которые будут отправляться на сервер. Можем их изменить (вставим php 7, python и javascript по очереди) и отправляем кнопкой "Try it out" изменения на сервер. Теперь в браузере, перейдя по ссылке, мы увидим наши новые три блога:

Так как сейчас у нас данные моделей хранятся в памяти, то при перезапуске экземпляра, все ноды, сохраненные нами до этой записи, конечно, потеряются. Для того, чтобы этого не происходило, на первоначальном этапе можно положить их в файл. Для этого нам потребуется всего одна строчка кода:

{
     "db": {
          "name": "db",
          "connector": "memory",
          "file": "db.json"
     }
}

Ее надо добавить в файле ./server/datasource.json. Все, теперь наши данные никуда после перезагрузки не пропадут.

Немного автоматизации

Для того, чтобы каждый раз не перезапускать ноду, давайте установим дополнительную утилиту - nodemon и добавим скрипт в npm удобным для вас вариантом:

npm i nodemon --save-dev #  локально в проекте
npm i nodemon -g # глобально в системе

После, в package.json добавляем команду в раздел scripts:

"dev": "nodemon server/server.js --watch common --watch server"

После этого нам не нужно больше перезапускать ноду каждый раз для применения изменений. Nodemon автоматически ее будет за нас перезапускать.

Выстраиваем отношения

Для начала необходимо добавить новое поле в модель Article. Для этого выполним команду и проследуем инструкциям консольной утилиты:

lb property

Выбираем модель из списка, вводим имя поля blog_id, выбираем тип поля number, ставим обязательно и оставляем без значения по умолчанию.

Затем, надо создать описание отношений в наших моделях:

lb relation

Сначала выбираем модель Blog. Указываем ей тип отношений has many. Выбираем модель для отношений Article. Далее название отношения оставляем по умолчанию, нажимая enter. После этого вводим название ключа, по которому будет связана модель blog_id. Остальные пункты пропускаем по умолчанию.

Теперь разбираемся с моделью Article. Указываем ей тип отношений belongs to. Выбираем модель для отношений Blog. Далее название отношения оставляем по умолчанию, нажимая enter. После этого вводим название ключа, по которому будет связана модель blog_id. Остальные пункты пропускаем по умолчанию.

Настройка отношений двух моделей между собой закончена. Попробуем проверить это. Идем в уже знакомый нам explorer (не IE) и добавляем пару статей с привязкой к блоку. Открываем POST /Articles и добавляем статьи:

После добавления отношений между моделями у нас появились дополнительные API. Можно например по url GET Articles/{id}/blog вывести запись блога, в котором находится данная статья. Или по url GET Blogs/{id}/articles вывести все статьи блога по id. В общем, наши возможности после добавления отношений стали намного шире. Отношения затронули и сами json файлы наших моделей.

Article.json

{
  "name": "Article",
  "base": "PersistedModel",
  "idInjection": false,
  "options": {
  "validateUpsert": true
  },
  "properties": {
    "title": {
      "type": "string",
      "required": true,
      "default": "New article"
    },
    "body": {
      "type": "string",
      "required": true
    },
    "blog_id": {
      "type": "number",
      "required": true
    },
    "votes": {
      "type": "number",
      "required": true,
      "default": 0
    }
  },
  "validations": [],
  "relations": {
    "blog": {
      "type": "belongsTo",
      "model": "Blog",
      "foreignKey": "blog_id"
    }
  },
  "acls": [],
  "methods": {}
}

Blog.json

{
  "name": "Blog",
  "base": "PersistedModel",
  "idInjection": false,
  "options": {
         "validateUpsert": true
  },
  "properties": {
    "title": {
      "type": "string",
      "required": true
    },
    "description": {
      "type": "string"
    }
},
  "validations": [],
  "relations": {
    "articles": {
      "type": "hasMany",
      "model": "Article",
      "foreignKey": "blog_id"
    }
  },
  "acls": [],
  "methods": {}
}

Вместо заключения

На данном этапе мы развернули простое приложение с помощью утилиты фреймворка, создали две простые модели, соединили их отношением. Сделали мы это все достаточно быстро и просто, но при этом получили уже разнообразное API для управления блогами и статьями. В следующей части мы рассмотрим более интересные вопросы, такие, как кастомные методы в API моделей, дополнительная валидация данных, хуки моделей и установку прав выполнения операций (ACL). 

Скачать исходники можно тут:

git clone https://github.com/dionic-i/lb-blog.git

После загрузки переходим в папку проекта:

npm i
git checkout beginning
npm run dev