Node.js, Express и MongoDB: API за полчаса

https://medium.freecodecamp.com/building-a-simple-node-js-api-in-under-30-minutes-a07ea9e390d2#.eybmlr1g9
  • Перевод
Начинающему программисту разработка для 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 в реальных проектах, может быть, вы посоветуете что-нибудь полезное новичкам? А если вы только что всё это впервые попробовали – ждём ваших впечатлений.
RUVDS.com 559,45
RUVDS – хостинг VDS/VPS серверов
Поделиться публикацией
Комментарии 27
  • 0
    Насколько я знаю, соединение с монгой может быть утеряно. То, как сделано сейчас (единожды коннектимся к базе при старте приложения) не очень надежно. Поэтому по-хорошему нужно перед каждым взаимодействием с базой проверять, что соединение в порядке и в случае надобности делать новый коннект. Чтоб не делать этого каждый раз, есть удобная мидлвара, которая держит объект соединения в замыкании и при каждом запросе пользователя проверяет наличие соединения, делает рекконнект (если нужно), и записывает объект базы данных в req.
    • –1
      А можно просто взять mongoose и получить автоподключение + ORM.
      • 0

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

          • 0
            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 таймер на событие отрубания и если оно не приконнектится через нужное время, значит база мертва / канал мертв.
            • 0

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


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

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


              Варианты:


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

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

      • 0
        так там автоматически создаётся пул из 5 соединений. Его размер хранится в db.poolSize
        • 0
          В db.url можно добавить параметр autoReconnect=true, хотя оно вроде бы было включено по-умолчанию
        • –1
          Еще дополнение. Где-то в документации натыкался, что лучше использовать express.Router()

          Кстати, мне кажется что его удобнее использовать и не надо пробрасывать app внутрь.
          • 0
            а даже если и пробрасывать app — зачем пробрасывать db, когда ее можно сделать свойством app и обращаться через штатные set / get методы.
            • 0
              Это мне вопрос? Я не автор статьи.
              • 0
                Вопрос? Нет, это просто дополнение к комментарию — к мысли о том, что можно не прокидывать лишнее в виде параметров.
                • 0
                  Ок, показалось что вопрос адресовался мне.

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

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

                      Но если что-то нужно в middleware то да, правильный подход.
            • 0
              http://expressjs.com/ru/guide/routing.html
              Последние абзацы
              • 0
                К сожалению описание, где это видел не помню. Но это не в официальной доке. Возможно где-то на GitHub в обсуждениях. Увы.

                Но для себя выбрал путь, когда роутинг это отдельный файл с описанием всех АПИ, а middleware разложены по модулям и импортируются в роут. Это позволяет наглядно видеть все АПИ, и при этом быстро получить доступ к реализации. Так же это позволяет вынести определение АПИ из index.js который теперь состоит из импортов модулей и их подключений. Файл становится небольшим и легко читаемым.
            • 0
              Желательно что бы URL имел примерно такой вид:
              /api/api_version/model_name
              Может оказаться, что API — это часть Вашего большого проекта.
              У Вашего проекта может быть несколько версий API.
              Хорошая статья про API
              • 0
                /api/api_version/model_name

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

                Альтернативы:
                1. Версия записывается в headers
                2. Версионируем каждый из ресурсов, т.е. /api/model_name/api_version
                3. ContentType, Accept
                и т.д.
                А, ну и вы вообще можете версионировать для каждого пользователя (так делают в Stripe, не совсем для каждого, но после регистрации для пользователя фиксируется версия api, т.е. пользователь совсем не знает какую версию он использует, и доку видит ту, которая для его api)
                • 0
                  Stripe просто монстры API. Не каждый такое осилит реализовать.
                  • 0
                    Да это было просто пример. Я бы такое врятли стал в своих проектах делать, масштаб не тот.
              • +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.

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

                    Подытожу: просто вываливать наружу методы хранилища проксируя через ноду недостаточно, чтобы называться REST.
                • 0
                  как я понял из документации более лучшей практикой является использование express.Router() вместо передачи app как параметра.

                  в файле users.js
                  const express = require('express');
                  const router = express.Router();
                  
                  router.get('/', function(req, res, next) {
                    res.json({ a: 1 });
                  });
                  

                  и в файле app.js
                  const express = require('express');
                  const app = express();
                  
                  app.use('/users', require('./users'));
                  

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

                  Самое читаемое