Привет, Хабр! представляю вашему вниманию перевод статьи «Creating a REST API: Web Server Basics».
Веб-сервер является одним из наиболее важных компонентов REST API. В этом посте вы начнете свой проект API REST, создав несколько начальных каталогов и файлов. Затем вы создадите модуль веб-сервера и подключите его так, чтобы веб-сервер запускался и правильно выключался.
Код в этом проекте будет организован с использованием общей структуры каталогов, которая может быть скорректирована и с течением времени построена по мере необходимости.
Файл index.js можно рассматривать как «основной» файл в приложении. Он будет точкой входа в приложение. Мы будем добавлять код в этот файл и файлы web-server.js в каталогах config и services.
Вставьте следующий код в файл Home > hr_app > config>web-server.js
В Node.js объект процесса имеет свойство env, которое содержит пользовательскую среду. Я использую это, чтобы установить значение порта в значение переменной среды HTTP_PORT. Если эта переменная среды не определена, значением по умолчанию будет 3000.
Вставьте следующий код в файл Home > hr_app > services>web-server.js
Строки 1-3: требуется несколько модулей. Модуль http включен в Node.js, но модуль Express необходимо будет установить через npm.
Строки 7-27: объявлена функция с именем initialize. Функция немедленно возвращает promise, которое разрешается или отклоняется в зависимости от того, успешно ли запущен веб-сервер.
Строки 9-10: создается новое экспресс-приложение (которое на самом деле является просто функцией), а затем используется для создания http-сервера через модуль http.
Строки 12-14: метод get приложения используется для добавления обработчика для запросов GET, которые приходят по корневому пути (/). Функция обратного будет вызываться при получении такого запроса, и она будет использовать параметр «res» (res) для отправки ответа «Hello World!» Клиенту.
Строки 16-24: метод прослушивания сервера используется для привязки к указанному порту и запуска прослушивания входящих запросов.
Строка 28: экспорт модуля чтоб можно было использовать извне
Вставьте следующий код в файл Home > hr_app > index.js
Подключаем модуль веб-сервера, а затем он определяет и вызывает асинхронную функцию startup. Поскольку функция initialize веб-сервера возвращает promise, вы можете использовать его с async / await и обернуть его в блок try-catch. Если функция initialize завершается успешно, веб-сервер будет работать; в противном случае любые исключения будут перехвачены и обработаны. Все, что вам нужно сделать сейчас, это инициализировать npm и установить Express — тогда вы можете запустить приложение. Выполните следующие команды в терминале из каталога hr_app.
Команда npm init используется для создания файла package.json, который npm использует как manifest файл (флаг -y принимает параметры по умолчанию). Команда npm install используется для установки express (флаг -s добавляет express в список зависимостей в package.json). Npm хранит установленные вами модули в каталоге node_modules. Он также создает файл с именем package.lock.json, чтобы обеспечить идентичное дерево для команды разработчиков.
Вы видите сообщение Web server listening on localhost:3000? Поздравляем, вы создали экспресс-сервер на базе!
И вот он, еще один «Hello World». Хотя это и не особенно увлекательно, это важный первый шаг для вашего API.
Когда будете готовы, можете выключить сервер, вернувшись к терминалу и нажав ctrl + c.

Во время выключения нажатием Ctrl + C у вас нет контроля над тем, как это произошло. Чтобы контролировать процесс завершения работы, вам необходимо явно закрыть веб-сервер и выйти из процесса Node.js.
Вставьте следующий код в файл Home > hr_app >services>web-server.js
Функция close возвращает promise, который разрешается при успешном закрытии веб-сервера. Метод httpServer.close останавливает установление новых соединений, но не заставляет закрывать уже открытые соединения. В зависимости от того, сколько соединений открыто и что они делают, вам может потребоваться немного подождать, пока не сработает обратный вызов. Хотя вы не будете делать это в этом модуле, для принудительного закрытия открытых соединений можно использовать пользовательский код или модули npm, такие как http-shutdown.
Вставьте следующий код в файл Home > hr_app > index.js
События SIGINT и SIGTERM относятся к сигналам, которые могут быть отправлены процессу для его выключения, например, когда нажаты ctrl + c. Событие uncaughtException произойдет, когда ошибка JavaScript генерируется, но не перехватывается и обрабатывается с помощью оператора try-catch. Попробуйте запустить и снова закрыть приложение. Вы узнаете, что все работает правильно, когда увидите сообщения «выключения» в терминале.
Есть еще одна вещь, которая завершает наш модуль веб-сервера: HTTP logging. Существуют различные модули, которые вы можете использовать для этого типа логинига, но morgan Один из простых. Давайте установим morgan с помощью npm.
Затем добавьте следующую строку в services / web-server.js под строкой, которая требует express (строка 2):
Теперь вы можете включить функцию morgan в качестве промежуточного программного обеспечения, через которую все запросы будут обрабатываться с помощью app.use. Добавьте эту строку перед вызовом app.get, который выдает сообщение «hello world».
Обратите внимание, что app.use создает конвейер (pipeline) функций промежуточного программного обеспечения (middleware), которые могут взаимодействовать с HTTP-запросами и ответами. Функции middleware будет выполняться в том порядке, в котором они включены. Перезапустите приложение и установите терминал так, чтобы вы могли видеть его и браузер одновременно. Каждый раз, когда вы перезагружаете страницу, вы должны видеть, что в терминале появляется новая запись в журнале. По умолчанию morgan передает информацию журнала в STDOUT (который отображается в терминале).
Следующая статья будет посвящена основам работы с базами данных, включая пулы соединений, которые помогут вам понять и построить API REST для Node.js.
Часть 1. Создание REST API: основы веб-сервера
Веб-сервер является одним из наиболее важных компонентов REST API. В этом посте вы начнете свой проект API REST, создав несколько начальных каталогов и файлов. Затем вы создадите модуль веб-сервера и подключите его так, чтобы веб-сервер запускался и правильно выключался.
Код в этом проекте будет организован с использованием общей структуры каталогов, которая может быть скорректирована и с течением времени построена по мере необходимости.
cd ~ mkdir hr_app cd hr_app/ touch index.js mkdir config touch config/web-server.js mkdir controllers mkdir db_apis mkdir services touch services/web-server.js
Файл index.js можно рассматривать как «основной» файл в приложении. Он будет точкой входа в приложение. Мы будем добавлять код в этот файл и файлы web-server.js в каталогах config и services.
Вставьте следующий код в файл Home > hr_app > config>web-server.js
module.exports = { port: process.env.HTTP_PORT || 3000 };
В Node.js объект процесса имеет свойство env, которое содержит пользовательскую среду. Я использую это, чтобы установить значение порта в значение переменной среды HTTP_PORT. Если эта переменная среды не определена, значением по умолчанию будет 3000.
Вставьте следующий код в файл Home > hr_app > services>web-server.js
const http = require('http'); const express = require('express'); const webServerConfig = require('../config/web-server.js'); let httpServer; function initialize() { return new Promise((resolve, reject) => { const app = express(); httpServer = http.createServer(app); app.get('/', (req, res) => { res.end('Hello World!'); }); httpServer.listen(webServerConfig.port) .on('listening', () => { console.log(`Web server listening on localhost:${webServerConfig.port}`); resolve(); }) .on('error', err => { reject(err); }); }); } module.exports.initialize = initialize;
Строки 1-3: требуется несколько модулей. Модуль http включен в Node.js, но модуль Express необходимо будет установить через npm.
Строки 7-27: объявлена функция с именем initialize. Функция немедленно возвращает promise, которое разрешается или отклоняется в зависимости от того, успешно ли запущен веб-сервер.
Строки 9-10: создается новое экспресс-приложение (которое на самом деле является просто функцией), а затем используется для создания http-сервера через модуль http.
Строки 12-14: метод get приложения используется для добавления обработчика для запросов GET, которые приходят по корневому пути (/). Функция обратного будет вызываться при получении такого запроса, и она будет использовать параметр «res» (res) для отправки ответа «Hello World!» Клиенту.
Строки 16-24: метод прослушивания сервера используется для привязки к указанному порту и запуска прослушивания входящих запросов.
Строка 28: экспорт модуля чтоб можно было использовать извне
Вставьте следующий код в файл Home > hr_app > index.js
const webServer = require('./services/web-server.js'); async function startup() { console.log('Starting application'); try { console.log('Initializing web server module'); await webServer.initialize(); } catch (err) { console.error(err); process.exit(1); // Non-zero failure code } } startup();
Подключаем модуль веб-сервера, а затем он определяет и вызывает асинхронную функцию startup. Поскольку функция initialize веб-сервера возвращает promise, вы можете использовать его с async / await и обернуть его в блок try-catch. Если функция initialize завершается успешно, веб-сервер будет работать; в противном случае любые исключения будут перехвачены и обработаны. Все, что вам нужно сделать сейчас, это инициализировать npm и установить Express — тогда вы можете запустить приложение. Выполните следующие команды в терминале из каталога hr_app.
npm init -y npm install express -s node .
Команда npm init используется для создания файла package.json, который npm использует как manifest файл (флаг -y принимает параметры по умолчанию). Команда npm install используется для установки express (флаг -s добавляет express в список зависимостей в package.json). Npm хранит установленные вами модули в каталоге node_modules. Он также создает файл с именем package.lock.json, чтобы обеспечить идентичное дерево для команды разработчиков.
Вы видите сообщение Web server listening on localhost:3000? Поздравляем, вы создали экспресс-сервер на базе!
И вот он, еще один «Hello World». Хотя это и не особенно увлекательно, это важный первый шаг для вашего API.
Когда будете готовы, можете выключить сервер, вернувшись к терминалу и нажав ctrl + c.

Контролируемый shutdown
Во время выключения нажатием Ctrl + C у вас нет контроля над тем, как это произошло. Чтобы контролировать процесс завершения работы, вам необходимо явно закрыть веб-сервер и выйти из процесса Node.js.
Вставьте следующий код в файл Home > hr_app >services>web-server.js
// *** previous code above this line *** function close() { return new Promise((resolve, reject) => { httpServer.close((err) => { if (err) { reject(err); return; } resolve(); }); }); } module.exports.close = close;
Функция close возвращает promise, который разрешается при успешном закрытии веб-сервера. Метод httpServer.close останавливает установление новых соединений, но не заставляет закрывать уже открытые соединения. В зависимости от того, сколько соединений открыто и что они делают, вам может потребоваться немного подождать, пока не сработает обратный вызов. Хотя вы не будете делать это в этом модуле, для принудительного закрытия открытых соединений можно использовать пользовательский код или модули npm, такие как http-shutdown.
Вставьте следующий код в файл Home > hr_app > index.js
// *** previous code above this line *** async function shutdown(e) { let err = e; console.log('Shutting down'); try { console.log('Closing web server module'); await webServer.close(); } catch (e) { console.log('Encountered error', e); err = err || e; } console.log('Exiting process'); if (err) { process.exit(1); // Non-zero failure code } else { process.exit(0); } } process.on('SIGTERM', () => { console.log('Received SIGTERM'); shutdown(); }); process.on('SIGINT', () => { console.log('Received SIGINT'); shutdown(); }); process.on('uncaughtException', err => { console.log('Uncaught exception'); console.error(err); shutdown(err); });
События SIGINT и SIGTERM относятся к сигналам, которые могут быть отправлены процессу для его выключения, например, когда нажаты ctrl + c. Событие uncaughtException произойдет, когда ошибка JavaScript генерируется, но не перехватывается и обрабатывается с помощью оператора try-catch. Попробуйте запустить и снова закрыть приложение. Вы узнаете, что все работает правильно, когда увидите сообщения «выключения» в терминале.
Регистрация на сервере
Есть еще одна вещь, которая завершает наш модуль веб-сервера: HTTP logging. Существуют различные модули, которые вы можете использовать для этого типа логинига, но morgan Один из простых. Давайте установим morgan с помощью npm.
npm install morgan -s
Затем добавьте следующую строку в services / web-server.js под строкой, которая требует express (строка 2):
const morgan = require('morgan');
Теперь вы можете включить функцию morgan в качестве промежуточного программного обеспечения, через которую все запросы будут обрабатываться с помощью app.use. Добавьте эту строку перед вызовом app.get, который выдает сообщение «hello world».
// Combines logging info from request and response app.use(morgan('combined')); // *** app.get call below this line ***
Обратите внимание, что app.use создает конвейер (pipeline) функций промежуточного программного обеспечения (middleware), которые могут взаимодействовать с HTTP-запросами и ответами. Функции middleware будет выполняться в том порядке, в котором они включены. Перезапустите приложение и установите терминал так, чтобы вы могли видеть его и браузер одновременно. Каждый раз, когда вы перезагружаете страницу, вы должны видеть, что в терминале появляется новая запись в журнале. По умолчанию morgan передает информацию журнала в STDOUT (который отображается в терминале).
Следующая статья будет посвящена основам работы с базами данных, включая пулы соединений, которые помогут вам понять и построить API REST для Node.js.
