Начинающему программисту разработка для Node.js может показаться сущим кошмаром. Виной всему – гибкость этой платформы и отсутствие чётких руководств. Но, на самом деле, всё не так уж и страшно.


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

Один из способов создания серверной части приложения заключается в применении связки из Node.js, фреймворка Express и СУБД MongoDB. Собственно говоря, сегодня я расскажу о том, как создать рабочий макет API, который может служить основой для практически любого приложения. Здесь мы реализуем основные маршруты REST, будем взаимодействовать с API по HTTP и использовать простые варианты работы с базой данных.

Для того, чтобы успешно освоить этот материал, вам надо понимать, что такое REST API, иметь представление об операциях CRUD и обладать базовыми знаниями в области JavaScript. Здесь я использую ES6, ничего особенно сложного, в основном – стрелочные функции.

Мы разработаем скелет серверной части приложения для создания заметок, похожего на Google Keep. При этом с заметками можно будет выполнять все четыре CRUD-действия, а именно – создание (create), чтение (read), обновление (update), и удаление (delete).

Предварительная подготовка


Если Node у вас пока нет, самое время его установить. После установки создайте папку и выполните в ней команду инициализации нового проекта:

npm init

В ходе инициализации ответьте на вопросы, в частности, дайте приложению имя «notable» (или, если хотите, любое другое).

Теперь в папке должен появиться файл package.json. Это означает, что можно начать устанавливать дополнительные пакеты, от которых зависит проект.

В качестве фреймворка мы планируем использовать Express. Системой управления базами данных будет MongoDB. Кроме того, в качестве вспомогательного средства для работы с JSON, используем пакет body-parser. Установим всё это:

npm install --save express mongodb body-parser

Ещё, я очень рекомендую установить Nodemon как dev-зависимость. Это простой маленький пакет, который, при изменении файлов, автоматически перезапускает сервер.

Для установки этого пакета выполните команду:

npm install --save-dev nodemon

Затем можно добавить следующий скрипт в файл package.json:

// package.json
  "scripts": {
    "dev": "nodemon server.js"
  },

Готовый package.json будет выглядеть примерно так:

// package.json
{
  "name": "notable",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "dev": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "mongodb": "^2.2.16"
  },
  "devDependencies": {
    "nodemon": "^1.11.0"
  }
}

Теперь создадим файл server.js и приступим к работе над API.

Сервер


Начнём с подключения зависимостей в файле server.js.

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();

MongoClient будем использовать для взаимодействия с базой данных. Кроме того, здесь мы инициализируем константу app, символизирующую наше приложение, экземпляром фреймворка Express. Чтобы сервер заработал, осталось лишь указать приложению на то, чтобы оно начало прослушивать HTTP-запросы.

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

// server.js
const port = 8000;
app.listen(port, () => {
  console.log('We are live on ' + port);
});

Теперь, если выполнить команду npm run dev (или – node server.js, если вы не устанавливали Nodemon), в терминале должно появиться сообщение: «We are live on port 8000».

Итак, сервер работает. Но сейчас он не делает совершенно ничего полезного. Давайте с этим разберёмся.

Маршруты, ориентированные на CRUD-операции


Мы планируем создать 4 маршрута. А именно:

  • CREATE – создание заметок.
  • READ –чтение заметок.
  • UPDATE –обновление заметок.
  • DELETE –удаление заметок.

Освоив эту схему, вы сможете понять, как, с помощью Node, организовать практически любой необходимый REST-маршрут.

Для того, чтобы протестировать API, понадобится нечто, способное имитировать запросы клиентской части приложения. Решить эту задачу нам поможет отличная программа, которая называется Postman. Она позволяет выполнять простые HTTP-запросы с заданным телом и параметрами.

Установите Postman. Теперь всё готово к настройке маршрутов.

О структуре проекта


В большинстве руководств по Node.js (и во множестве реальных приложений) все маршруты размещают в одном большом файле route.js. Мне такой подход не очень нравится. Если разложить файлы по разным папкам, это улучшит читаемость кода, приложением будет легче управлять.

Наше приложение большим не назовёшь, но предлагаю сделать всё как надо, учитывая, всё же, его скромные масштабы. Создайте следующие папки: папку app, а внутри неё – routes. В папке routes создайте файлы index.js и note_routes.js. Другими словами, структура проекта будет выглядеть так: root > app > routes > index.js и note_routes.js.

mkdir app
cd app
mkdir routes
cd routes
touch index.js
touch note_routes.js

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

Создание заметок: маршрут CREATE


Начнём с маршрута CREATE. Для этого ответим на вопрос: «Как создать заметку?».
Прежде чем приступить к созданию заметок, нам понадобится расширить инфраструктуру приложения. В Express маршруты оборачивают в функцию, которая принимает экземпляр Express и базу данных как аргументы.

Выглядеть это может так:

// routes/note_routes.js
module.exports = function(app, db) {
};

Теперь можно экспортировать эту функцию через index.js:

// routes/index.js
const noteRoutes = require('./note_routes');
module.exports = function(app, db) {
  noteRoutes(app, db);
  // Тут, позже, будут и другие обработчики маршрутов 
};

Импортируем то, что получилось, в server.js:

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();
const port = 8000;
require('./app/routes')(app, {});
app.listen(port, () => {
  console.log('We are live on ' + port);
});

Обратите внимание на то, что так как базу данных мы пока не настроили, вторым аргументом передаётся пустой объект.

Теперь создаём маршрут CREATE. Синтаксис здесь довольно простой:

module.exports = function(app, db) {
  app.post('/notes', (req, res) => {
    // Здесь будем создавать заметку.
    res.send('Hello')
  });
};

Когда приложение получает POST-запрос по пути ‘/notes’, оно исполнит код внутри функции обратного вызова, передав ей объект запроса (который содержит параметры запроса или JSON-данные) и объект ответа (который, понятно, используется для ответа).

То, что у нас получилось, уже можно протестировать. Отправим, с помощью Postman, POST-запрос по адресу localhost:8000/notes.


В ответ на запрос должно прийти «Hello»

Отлично. Первый маршрут создан. Следующий шаг – добавление к запросу параметров, обработка их в API, и, наконец – сохранение заметки в базе данных.

Параметры запроса


В Postman перейдите на вкладку Body и добавьте несколько пар ключ-значение, выбрав радиокнопку x-www-form-urlencoded. А именно, первым ключом будет title, его значение – My Note Title. Второй ключ – body, его значение – What a great note.

Это добавит к запросу закодированные данные, которые можно будет обработать в API.


Заголовок моей заметки, да и она сама – очень просты, а вы тут можете проявить фантазию

В файле note_route.js, просто выведем тело заметки в консоль.

// note_routes.js
module.exports = function(app, db) {
  app.post('/notes', (req, res) => {
    console.log(req.body)
    res.send('Hello')
  });
};

Попробуйте отправить запрос с помощью Postman, и вы увидите… undefined.

К сожалению, Express не может самостоятельно обрабатывать формы в URL-кодировке. Тут нам на помощь придёт ранее установленный пакет body-parser.

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
require('./app/routes')(app, {});
app.listen(port, () => {
  console.log('We are live on ' + port);
});

Теперь, после выполнения POST-запроса, его тело можно будет увидеть в терминале в виде объекта.

{ title: 'My Note Title', body: 'What a great note.' }

Чтобы первый маршрут полностью заработал, осталось лишь настроить базу данных и добавить в неё заметку.

Для быстрого создания и настройки базы данных воспользуемся сервисом mLab. Работать с ним легко, для маленьких объёмов информации он бесплатен.

Создайте учётную запись на сайте mLab и разверните новую базу данных MongoDB. Для этого нажмите на кнопку Create New в разделе MongoDB Deployments, в появившемся окне, в разделе Plan, выберите Single-node. В списке Standard Line, выберите Sandbox и дайте базе данных имя. Далее, в окне управления базой, перейдите на вкладку Users и добавьте пользователя базы данных, задав имя и пароль.


Новый пользователь базы данных

Скопируйте с той же страницы второй URL – строку подключения к базе данных.


URL для подключения к базе данных

В корень проекта добавьте директорию config, создайте в ней файл db.js.

mkdir config 
cd config
touch db.js

В файл db.js добавьте следующее:

module.exports = {
  url : здесь будет ваш URL
};

Не забудьте добавить в URL имя пользователя и пароль (не те, что от учётной записи в mLab, а те, что создавали для базы данных). Если вы размещаете проект на Github, не забудьте включить в него файл .gitignore (вроде этого). Так вы не сделаете всеобщим достоянием имя и пароль для работы с базой.

Теперь, в server.js, можно использовать MongoClient для подключения к базе данных и обернуть в функцию, которая передаётся ему при создании, настройки приложения:

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const db             = require('./config/db');
const app            = express();
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
MongoClient.connect(db.url, (err, database) => {
  if (err) return console.log(err)
  require('./app/routes')(app, database);
  app.listen(port, () => {
    console.log('We are live on ' + port);
  });               
})

На этом подготовка инфраструктуры закончена. С этого момента будем заниматься исключительно путями.

Добавление записей в базу данных


MongoDB хранит данные в коллекциях (collections), которые полностью оправдывают своё название. В нашем случае заметки будут храниться в коллекции, которая, как несложно догадаться, будет называться notes.

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

db.collection('notes')

Создание заметки в базе равносильно вызову команды insert для коллекции notes:

const note = { text: req.body.body, title: req.body.title}
  db.collection('notes').insert(note, (err, results) => {
}

После успешного завершения команды (или после того, как она, по какой-нибудь причине, не сможет выполниться), нужно либо отправить в ответ только что созданный объект заметки, либо – сообщение об ошибке. Вот код note_routes.js, дополненный с учётом этих рассуждений:

// note_routes.js
module.exports = function(app, db) {
  app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

Испытайте то, что получилось. Отправьте из Postman POST-запрос (с флагом x-www-form-urlencoded ), задав на вкладке Body значения полей title и body.

Ответ должен выглядеть примерно так:


Успешное добавление записи в базу

Если теперь посмотреть на базу, авторизовавшись на mLab, в ней можно будет найти только что созданную заметку.

Чтение заметок: маршрут READ


Инфраструктура, которую мы подготовили выше, подходит для всех маршрутов, поэтому теперь дело пойдёт быстрее.

Итак, мы собираемся запросить только что созданную заметку, пройдя по пути localhost:8000/notes/{id заметки}. В нашем случае путь будет выглядеть так: localhost:8000/notes/585182bd42ac5b07a9755ea3.

Если ID одной из уже созданных заметок у вас нет, можете заглянуть в базу на mLab и найти его там, или создать новую заметку и скопировать её идентификатор.

Вот как это выглядит в note_route.js:

// note_routes.js
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    
  });
  app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

Так же, как и раньше, мы собираемся вызвать некую команду для коллекции базы данных заметок. Применим для этого метод findOne.

// note_routes.js
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    const details = { '_id': <ТУТ БУДЕТ ID> };
    db.collection('notes').findOne(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send(item);
      }
    });
  });
app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

Идентификатор из параметров URL можно вытащить с помощью конструкции req.params.id. Однако если просто вставить строку вместо <<>> из кода выше, работать это не будет.

MongoDB требуется ID не в виде строки, а в виде специального объекта. Он называется ObjectID.

Вот что, после небольших изменений, у нас получилось:

// note_routes.js
var ObjectID = require('mongodb').ObjectID;
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    db.collection('notes').findOne(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send(item);
      } 
    });
  });
app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

Испытайте это с одним из идентификаторов заметок, имеющихся в базе данных. Ответ в Postman должен выглядеть так:


Успешный запрос заметки из базы

Удаление заметок: маршрут DELETE


Удаление объектов – это практически то же самое, что их поиск в базе. Только вместо функции findOne используется функция remove. Вот полный код соответствующего пути. Здесь выделено то, что отличается от кода уже существующего метода, обрабатывающего запрос GET.

// note_routes.js
// ...
  app.delete('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    db.collection('notes').remove(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send('Note ' + id + ' deleted!');
      } 
    });
  });
// ...

Обновление заметок: маршрут UPDATE


А вот и последний маршрут. Обработка запроса PUT – это, по сути, гибрид операций READ и CREATE. Сначала надо найти объект, потом – обновить его в соответствии с поступившими в запросе данными. Сейчас, если вы, испытывая предыдущий фрагмент кода, удалили свою единственную заметку, создайте ещё одну.

Вот код маршрута обновления заметок:

// note_routes.js
// ...
  app.put ('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').update(details, note, (err, result) => {
      if (err) {
          res.send({'error':'An error has occurred'});
      } else {
          res.send(note);
      } 
    });
  });
// ...

Теперь любую заметку можно редактировать. Вот, как это выглядит:


Успешное обновление заметки

Обратите внимание на недостаток нашего примера. Если в PUT-запросе не будет тела или заголовка заметки, соответствующие поля в базе будут просто очищены.

Я не нагружал пример дополнительными проверками. Если хотите, можете сами доработать операцию обновления заметок, внося в базу новые данные только в том случае, если запрос сформирован верно.

Итоги


Теперь у вас есть рабочее Node API, которое поддерживает четыре основные операции CRUD. Серверная часть приложения умеет, реагируя на HTTP-запросы клиента, создавать в базе данных заметки, находить их, удалять и редактировать.

Основная цель моего рассказа – познакомить всех желающих со связкой Node + Express + MongoDB и с методикой разработки серверных приложений. Конечно, если сегодня состоялось ваше первое знакомство с этими инструментами, для того, чтобы во всё лучше вникнуть, вам понадобится почитать документацию. Однако, понимание происходящего позволит вам быстро восполнить пробелы в знаниях и приступить к работе над собственными проектами, использовав, в качестве отправной точки, приложение, которым мы с вами тут занимались.

Если у вас есть опыт работы с Node.js, Express и MongoDB в реальных проектах, может быть, вы посоветуете что-нибудь полезное новичкам? А если вы только что всё это впервые попробовали – ждём ваших впечатлений.
Поделиться с друзьями
-->

Комментарии (24)


  1. f0rmat1k
    03.02.2017 17:01

    Насколько я знаю, соединение с монгой может быть утеряно. То, как сделано сейчас (единожды коннектимся к базе при старте приложения) не очень надежно. Поэтому по-хорошему нужно перед каждым взаимодействием с базой проверять, что соединение в порядке и в случае надобности делать новый коннект. Чтоб не делать этого каждый раз, есть удобная мидлвара, которая держит объект соединения в замыкании и при каждом запросе пользователя проверяет наличие соединения, делает рекконнект (если нужно), и записывает объект базы данных в req.


    1. Leopotam
      03.02.2017 17:14
      -1

      А можно просто взять mongoose и получить автоподключение + ORM.


      1. luther
        03.02.2017 21:16

        Ну прямо скажем mongoose не решает вопрос отвалившейся БД.
        Вот примерно так можно отслеживать состояние подключения: https://github.com/simdo/rest.api/blob/master/index.js


        1. luther
          04.02.2017 00:07

          1. Leopotam
            04.02.2017 00:17

            http://mongoosejs.com/docs/connections.html:

            Note: The server option auto_reconnect is defaulted to true which can be overridden. The db option forceServerObjectId is set to false which cannot be overridden.

            Note: If auto_reconnect is on, mongoose will give up trying to reconnect after a certain number of failures. Set the server.reconnectTries and server.reconnectInterval options to increase the number of times mongoose will try to reconnect.

            // Good way to make sure mongoose never stops trying to reconnect
            mongoose.connect(uri, { server: { reconnectTries: Number.MAX_VALUE } });
            


            Т.е. в принципе нет нужны в таком функционале. Можно сделать watchdog таймер на событие отрубания и если оно не приконнектится через нужное время, значит база мертва / канал мертв.


            1. luther
              04.02.2017 00:32

              Ну ребята, ну как же так?


              1. У меня rest микросервис.
              2. Данные обрабатываются в БД.
              3. БД удаленная.
              4. Соединение не стабильное.

              Вопрос:
              Какой ответ сервис должен отдать в случае когда клиент осуществляет api-запрос?
              Сервер в данный момент утерял соединение с БД.


              Варианты:


              • заставить клиента ожидать на линии
              • пробросить ошибку получения данных из БД ввиду отсутствия соединения?
              • ответить что в данный момент БД недоступна
              • ваши предложения?


              1. Leopotam
                04.02.2017 00:40

                Если соединение нестабильное, то у меня плохие новости — клиентам лучше поискать другие сервисы. Доступ к СУБД — одна из самых критичных к общей производительности системы вещей. Можно сделать локальное кеширование, сделать несколько копий базы с репликацией (но все-равно мастер на запись будет один). А вообще, да, 2 варианта:
                1. Показывать пользователю крутилку, что мы что-то делаем с разумным временем ожидания
                2. Отдать управление с показом варнинга, что операция продолжается в фоне и нужно подождать ее завершения (если настроены реплики с доступом на чтение — клиенту не обязательно ждать завершения операции сохранения для дальнейших операций поиска).
                Опять же — все зависит от задачи, допускается такое поведение или нет.


                1. luther
                  04.02.2017 08:56

                  Мой посыл заключается в том что приложение будет валить ошибки изза отсутствия связи с БД. Эти ошибки вываливать на фронт клиенту некошерно. Вы мне рассказываете что mongoose там что-то сам делает и хорошо.


    1. mak_ufo
      03.02.2017 23:23

      так там автоматически создаётся пул из 5 соединений. Его размер хранится в db.poolSize


    1. tuxx
      04.02.2017 00:28

      В db.url можно добавить параметр autoReconnect=true, хотя оно вроде бы было включено по-умолчанию


  1. Aries_ua
    03.02.2017 21:16
    -1

    Еще дополнение. Где-то в документации натыкался, что лучше использовать express.Router()

    Кстати, мне кажется что его удобнее использовать и не надо пробрасывать app внутрь.


    1. Leopotam
      03.02.2017 21:57

      а даже если и пробрасывать app — зачем пробрасывать db, когда ее можно сделать свойством app и обращаться через штатные set / get методы.


      1. Aries_ua
        03.02.2017 23:14

        Это мне вопрос? Я не автор статьи.


        1. Leopotam
          03.02.2017 23:17

          Вопрос? Нет, это просто дополнение к комментарию — к мысли о том, что можно не прокидывать лишнее в виде параметров.


          1. Aries_ua
            03.02.2017 23:34

            Ок, показалось что вопрос адресовался мне.

            Интересно, что лучше: проброс app внутрь модуля или все же делать как middleware?

            Сам делаю middleware.


            1. Leopotam
              03.02.2017 23:39

              app передается в каждом запросе как req.app. Т.е. инстанс клиента бд можно в момент инициализации сохранить в app через app.set(), а потом доставать в роутинге через req.app.get().


              1. Aries_ua
                03.02.2017 23:46

                Использую mongooseJS в нем такая необходимость отсутствует.

                Но если что-то нужно в middleware то да, правильный подход.


    1. ilnuribat
      03.02.2017 22:04

      http://expressjs.com/ru/guide/routing.html
      Последние абзацы


      1. Aries_ua
        03.02.2017 23:43

        К сожалению описание, где это видел не помню. Но это не в официальной доке. Возможно где-то на GitHub в обсуждениях. Увы.

        Но для себя выбрал путь, когда роутинг это отдельный файл с описанием всех АПИ, а middleware разложены по модулям и импортируются в роут. Это позволяет наглядно видеть все АПИ, и при этом быстро получить доступ к реализации. Так же это позволяет вынести определение АПИ из index.js который теперь состоит из импортов модулей и их подключений. Файл становится небольшим и легко читаемым.


  1. SageVS
    03.02.2017 23:23

    Желательно что бы URL имел примерно такой вид:
    /api/api_version/model_name
    Может оказаться, что API — это часть Вашего большого проекта.
    У Вашего проекта может быть несколько версий API.
    Хорошая статья про API


    1. sentyaev
      04.02.2017 02:04

      /api/api_version/model_name

      Не обязательно.
      Есть несколько стратегий версионирования, и приведенная вами только одна из них.

      Альтернативы:
      1. Версия записывается в headers
      2. Версионируем каждый из ресурсов, т.е. /api/model_name/api_version
      3. ContentType, Accept
      и т.д.
      А, ну и вы вообще можете версионировать для каждого пользователя (так делают в Stripe, не совсем для каждого, но после регистрации для пользователя фиксируется версия api, т.е. пользователь совсем не знает какую версию он использует, и доку видит ту, которая для его api)


  1. igordata
    04.02.2017 06:13
    +1

    *не увидел, что это перевод

    Вопросы, которые я хотел бы задать автору:

    А что делает ваше CRUD API именно REST API? Какая часть статьи показывает наличие REST функционала в вашем CRUD API?

    вам надо понимать, что такое REST API, иметь представление об операциях CRUD
    Не могли бы вы добавить в вашу статью хотя бы небольшое пояснение по поводу того, что такое CRUD и что такое REST, и как сделать REST API на основе CRUD операций, и чем это лучше например REST поверх RPC, и почему вы выбрали именно CRUD? И как сможете всегда-всегда обходиться четырьмя операциями в реальной жизни, т.к. если ввести хоть что-то, отличное от CRUD, то это уже будет не CRUD API, а просто некое API?

    Освоив эту схему, вы сможете понять, как, с помощью Node, организовать практически любой необходимый REST-маршрут.
    Не любое API с урлами является RESTful. Я честно говоря не вижу в вашем API ничего от REST.

    пойду переведу и задам.


    1. igordata
      04.02.2017 06:32

      Задал вопрос автору. Ответ принесу (если будет).


      1. igordata
        05.02.2017 09:46
        +1

        https://medium.com/@scottdomes/hi-igor-e5192ded55a1#.xsii8g1y7
        Автор толком ничего не ответил. Я так понял, что автор считает, что если CRUD поверх HTTP, то этого достаточно, и это уже REST и всё тут. Гипермедийность с его стороны в беседе не упомянута. Хотя на мой взгляд это основополагающий принцип, отличающий «просто апи» от «рест апи» примерно так же как «просто текст» отличается от «текста с ссылками». Мне кажется отличие это разительное, и ситуация, когда вам нужно знать всю карту всех урлов заранее и она никак не вытекает из ответов сервера кардинально отличается от гипермедийного рест, где задумано, что, как и в HTML, вы получаете ссылки в ответах на запросы, и можете путешествовать дальше.

        Подытожу: просто вываливать наружу методы хранилища проксируя через ноду недостаточно, чтобы называться REST.