[Из песочницы] Создание REST API с Node.js и базой данных Oracle
Привет, Хабр! представляю вашему вниманию перевод статьи «Creating a REST API: Web Server Basics».
Часть 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.