Обработка ошибок в Express.js
2 года назад·4 мин. на чтение
Пишем middleware для Express.js для обработки ошибок.
Из-за неопределенного характера JavaScript существует множество способов выполнения одной задачи. Это может стать как достоинством, так и недостатком, особенно при работе в более крупной команде. Именно здесь в игру вступают процессы и руководящие принципы.
Предусловия
- Установленный NodeJS
- Знание NodeJS и Express.js
- Знание того, как работает middleware в Express.js
Настройка проекта
Создадим базовое приложение Express.js с одним эндпоинтом. Этот эндпоинт (или ручка) будет методомPOST
, который принимает два входных параметра title
и author
.
Мы проверяем, существуют лиconst express = require('express'); const bodyParser = require('body-parser'); const app = express(); const port = 3000; app.use(bodyParser.json()); app.post('/post', async (req, res) => { const { title, author } = req.body; if (!title || !author) { return res.status(400).json({ status: 'error', message: 'Missing required fields: title or author' }); } try { const post = await db.post.insert({ title, author }); res.json(post); } catch (error) { return res.status(500).json({ status: 'error', message: 'Internal Server Error' }); } }); app.listen(port, () => console.log(`app is listening at http://localhost:${port}`) );
title
и author
, если нет, мы выбрасываем ошибку 400
и отправляем обратно JSON со статусом и сообщением.
Если title
и author
существуют, приложение все равно будет аварийно завершать работу, потому что db
не определена, и наш блок try
/catch
поймает его и отправит обратно ошибку 500
и JSON со статусом и сообщением.
Со временем, по мере роста количества эндпоинтов и проверок, ввод res.status(4xx).json({ some: JSON })
каждый раз может быстро стать громоздким, а также создать большую избыточность кода. Почему бы не сделать что-то вроде throw new BadRequest('message')
? Давайте посмотрим, как мы можем это реализовать.
Создание утилит для ошибок
Теперь создадим функции, которую мы можем использовать для генерации ошибок. Создадим новую папку/utils
и файл errors.js
.
Этот файл определяет, какие ошибки мы можем выбросить в нашем приложении. Класс// /utils/errors.js class GeneralError extends Error { constructor(message) { super(); this.message = message; } getCode() { if (this instanceof BadRequest) { return 400; } if (this instanceof NotFound) { return 404; } return 500; } } class BadRequest extends GeneralError { } class NotFound extends GeneralError { } module.exports = { GeneralError, BadRequest, NotFound };
GeneralError
расширяет Error
и используется для получения наших сообщений и кодов состояния.
Здесь у нас есть BadRequest
и NotFound
, которые расширяют GeneralError
. Мы также указываем их коды ошибок в блоке getCode
в GeneralError
.
Для простоты этой демонстрации у нас будут толькоBadRequest
и NotFound
. Если вы хотите добавить другие типы ошибок, все, что вам нужно сделать, это создать новый класс, который расширяет GeneralError
и обновить его код состояния внутри блока getCode
.
Создание middleware для обработки ошибок
Теперь мы сосредоточимся на реализации express middleware для обработки ошибок в нашем приложении. Создадим новый файл/middleware/handleErrors.js
.
Примечание: middleware для обработки ошибок принимает 4 аргумента (ошибка в качестве первого аргумента), а не 3 аргумента для обычного middleware . Функция middleware// /middleware/handleErrors.js const { GeneralError } = require('../utils/errors'); const handleErrors = (err, req, res, next) => { if (err instanceof GeneralError) { return res.status(err.getCode()).json({ status: 'error', message: err.message }); } return res.status(500).json({ status: 'error', message: err.message }); } module.exports = handleErrors;
handleErrors
проверяет, является ли переданная ошибка экземпляром GeneralError
. Если это так, мы возвращаем код состояния и тело JSON со статусом и сообщением.
Использование middleware для обработки ошибок
Давайте обновим наше приложение и эндпоинт, чтобы использовать наш недавно созданный middleware для обработки ошибок. Middleware для обработки ошибок должно быть помещено последним, после всех других middleware и маршрутов, чтобы оно функционировало должным образом.Во-первых, мы импортируемconst express = require('express'); const bodyParser = require('body-parser'); const handleErrors = require('./middleware/handleErrors'); const { BadRequest } = require('./utils/errors'); const app = express(); const port = 3000; app.use(bodyParser.json()); app.post('/post', async (req, res, next) => { const { title, author } = req.body; try { if (!title || !author) { throw new BadRequest('Missing required fields: title or author'); // строка 16 } const post = await db.post.insert({ title, author }); res.json(post); } catch (err) { next(err) } }); app.use(handleErrors); // строка 25 app.listen(port, () => console.log(`app is listening at http://localhost:${port}`) );
handleErrors
и регистрируем его как middleware, как показано в строке 25.
Мы также импортируем BadReqest
и обновляем строку 16, чтобы выбросить новый BadRequest
, если title
и author
отсутствуют.
Наконец, мы добавляем next
в качестве третьего аргумента в наш обработчик маршрута. Затем мы обновляем блок catch
, чтобы передать ошибки в next
чтобы наш обработчик ошибок мог обработать его.
Тестирование middleware для обработки ошибок
Для тестирования middleware используем Postman. Сначала мы делаем POST-запрос безbody
. Мы получаем ошибку 400 со статусом и сообщением в формате JSON.
Теперь давайте сделаем еще один запрос POST и передадим{ "status": "error", "message": "Missing required fields: title or author" }
title
и author
. На этот раз мы получаем ошибку 500 со статусом и сообщением в JSON.
Простое и чистое решение для обработки ошибок в приложении Express.js.{ "status": "error", "message": "db is not defined" }
Итоги
В этой статье мы рассмотрели, как создать middleware для обработки ошибок для приложения Express.js. Это позволит поддерживать чистоту кода с меньшим количеством избыточного кода. Все, что нам нужно сделать, это выбросить ошибку и передать сообщение. Эта реализация добавляет гибкость для добавления дополнительных классов ошибок для вашего приложения по мере необходимости.Как запустить бэкэнд на Node JS
2 года назад·3 мин. на чтение
В этой статье напишем простой бэкэнд на NodeJS. Этот сервер будет полезен для разработки веб-приложений.
Необходимые условия
Перед созданием бэкэнда на node js нужно, чтобы были установлены все необходимые библиотеки, IDE и ПО, а именно:- NodeJS и npm. Их можно скачать с официального сайта nodejs.org. npm установится автоматически вместе с NodeJS.
- Предпочитаемый IDE, например, Visual Studio Code.
- Опционально, установить git для удобной работы с кодом.
О приложении
В этой статье напишем небольшой REST API сервер, который будет отдавать список дел по GET запросу. Структура папок будет выглядеть следующим образом.my-app/
Создание бэкэнда на NodeJS
Запустим команду в папкеmy-app/
для инициализации проекта:
Эта команда создаст файлnpm init -y
package.json
. Ключ -y
заполнит все поля в package.json
значениями по умолчанию. Файл package.json
содержит информацию о проекте - название, версия, описание, список зависимостей, скрипты для запуска, сборки и тестирования. Все поля можно будет изменить и вручную после его создания.
После инициализации package.json
будет выглядеть следующим образом.
{ "name": "my-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Создадим файлnpm install express
index.js
. В нем будет находится код для запуска сервера. Если порт не задан в переменных среды, то будет использован порт 3010
.
// my-app/index.js const express = require('express'); const PORT = process.env.PORT || 3010; const app = express(); app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); next(); }); app.listen(PORT, () => { console.log(`Server listening on ${PORT}`); });
Запуск сервера
В полеscripts
файла my-app/package.json
добавим команду для запуска сервера. В результате сможем запускать наш сервер с помощью команды npm start
.
Из папки... "scripts": { "start": "node ./index.js" }, ...
my-app/
запустим команду npm start
. Если ошибок нет, получим сообщение, что сервер прослушивает порт 3010.
PS C:\tutorials-coding\nodejs-backend\my-app> npm start > my-app@1.0.0 start > node ./index.js Server listening on 3010
Создание API
API это интерфейс, с помощью которого приложение будет общаться с веб-сервером, т.е. запрашивать, изменять или удалять данные. Мы сможем получать эти данные, например, в веб-приложении на React. О том как, делать API запросы к серверу из React приложения, можно прочитать в этой статье. В нашем случае мы создадим API для получения списка дел в формате JSON. Создадим файл/my-app/todo-items.json
c объектами todo. Этот массив будем отдавать по запросу /api/todo-items
.
[ { "id": 1, "text": "Изучить Node JS", "done": true }, { "id": 2, "text": "Изучить JavaScript", "done": true }, { "id": 3, "text": "Изучить React JS", "done": true }, { "id": 4, "text": "Написать приложение", "done": false } ]
/api/todo-items
. Веб-приложение сможет отправлять на него GET
запрос.
Для того чтобы изменения применились нужно перезапустить NodeJS сервер. Для остановки скрипта в терминале, в котором запущен// my-app/index.js // ... const todoItems = require('./todo-items.json'); app.get('/api/todo-items', (req, res) => { res.json({ data: todoItems }); }); app.listen(PORT, () => { console.log(`Server listening on ${PORT}`); });
npm start
, нужно нажать Ctrl + C
(Command + C
). Далее снова запускаем npm start
.
Для проверки эндпоинта, вставим в адресную строку браузера http://localhost:3010/api/todo-items
. В результате получим такой ответ.

Отправка HTTP запроса к серверу
К этому моменту у нас уже есть рабочий сервер, который умеет принимать запросы и отдавать данные. Для проверки работы сервера вне веб-приложения можно воспользоваться такими программами как Postman или Insomnia.Автоматический перезапуск сервера после обновления кода
Ранее для того чтобы изменения исходного кода сервера вступили в силу, мы перезапускали сервер. Можно ускорить процесс разработки и автоматизировать эту часть с помощью инструмента nodemon. nodemon будет следить за файлами в каталоге, в котором был запущен nodemon, и если какие-либо файлы изменятся, он автоматически перезапустит ваше node js приложение. Установим nodemon как зависимость для разработки.Добавим новый скриптnpm install --save-dev nodemon
dev
в my-app/package.json
.
Далее запустим сервер следующим образом.... "scripts": { "dev": "nodemon ./index.js" }, ...
Теперь, после изменений в коде, увидим, что сервер перезапускается сам. Исходный кодnpm run dev