Магазин на JavaScript, часть 3 из 19. Добавляем классы контроллеров, обработка ошибок
14.11.2021
Теги: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • БазаДанных • ИнтернетМагазин • КаталогТоваров • Корзина • Фреймворк
Добавляем контроллеры
Сейчас функции, которые обрабатывают HTTP-запросы от клиента, расположены прямо в роутере. Но это задача контроллера, которых у нас будет несколько — для товаров, категорий, брендов и пользователей. Создаем директорию controllers
и внутри нее — файлы Product.js
, Category.js
, Brand.js
и User.js
.
class Product { async getAll(req, res) { res.status(200).send('Список всех товаров') } async getOne(req, res) { res.status(200).send('Получение одного товара') } async create(req, res) { res.status(200).send('Создание нового товара') } async update(req, res) { res.status(200).send('Обновление товара') } async delete(req, res) { res.status(200).send('Удаление товара') } } export default new Product()
class Category { async getAll(req, res) { res.status(200).send('Список всех категорий') } async getOne(req, res) { res.status(200).send('Получение одной категории') } async create(req, res) { res.status(200).send('Создание новой категории') } async update(req, res) { res.status(200).send('Обновление категории') } async delete(req, res) { res.status(200).send('Удаление категории') } } export default new Category()
class Brand { async getAll(req, res) { res.status(200).send('Список всех брендов') } async getOne(req, res) { res.status(200).send('Получение одного бренда') } async create(req, res) { res.status(200).send('Создание нового бренда') } async update(req, res) { res.status(200).send('Обновление бренда') } async delete(req, res) { res.status(200).send('Удаление бренда') } } export default new Brand()
class User { async signup(req, res) { res.status(200).send('Регистрация пользователя') } async login(req, res) { res.status(200).send('Вход в личный кабинет') } async check(req, res) { res.status(200).send('Проверка авторизации') } async getAll(req, res) { res.status(200).send('Список всех пользователей') } async getOne(req, res) { res.status(200).send('Получение одного пользователя') } async create(req, res) { res.status(200).send('Создание нового пользователя') } async update(req, res) { res.status(200).send('Обновление пользователя') } async delete(req, res) { res.status(200).send('Удаление пользователя') } } export default new User()
Теперь удаляем из маршрутов функции, а вместо них указываем методы контроллеров, которые будут обрабатывать HTTP-запросы.
import express from 'express' import ProductController from '../controllers/Product.js' const router = new express.Router() router.get('/getall', ProductController.getAll) router.get('/getone/:id([0-9]+)', ProductController.getOne) router.post('/create', ProductController.create) router.put('/update/:id([0-9]+)', ProductController.update) router.delete('/delete/:id([0-9]+)', ProductController.delete) export default router
import express from 'express' import CategoryController from '../controllers/Category.js' const router = new express.Router() router.get('/getall', CategoryController.getAll) router.get('/getone/:id([0-9]+)', CategoryController.getOne) router.post('/create', CategoryController.create) router.put('/update/:id([0-9]+)', CategoryController.update) router.delete('/delete/:id([0-9]+)', CategoryController.delete) export default router
import express from 'express' import BrandController from '../controllers/Brand.js' const router = new express.Router() router.get('/getall', BrandController.getAll) router.get('/getone/:id([0-9]+)', BrandController.getOne) router.post('/create', BrandController.create) router.put('/update/:id([0-9]+)', BrandController.update) router.delete('/delete/:id([0-9]+)', BrandController.delete) export default router
import express from 'express' import UserController from '../controllers/User.js' const router = new express.Router() router.post('/signup', UserController.signup) router.post('/login', UserController.login) router.get('/check', UserController.check) router.get('/getall', UserController.getAll) router.get('/getone/:id([0-9]+)', UserController.getOne) router.post('/create', UserController.create) router.put('/update/:id([0-9]+)', UserController.update) router.delete('/delete/:id([0-9]+)', UserController.delete) export default router
Обработка ошибок
Создаем директорию errors
, а внутри нее — файл AppError.js
, где опишем класс, расширяющий Error
.
class AppError extends Error{ constructor(status, message) { super(); this.status = status this.message = message } static badRequest(message) { return new AppError(404, message) } static internalServerError(message) { return new AppError(500, message) } static forbidden(message) { return new AppError(403, message) } } export default AppError
Теперь создаем директорию middleware
, а внутри нее файл ErrorHandler.js
с функцией ErrorHandler
.
import AppError from '../errors/AppError.js' const ErrorHandler = (err, req, res, next) => { if (err instanceof AppError) { return res.status(err.status).json({message: err.message}) } return res.status(500).json({message: 'Непредвиденная ошибка'}) } export default ErrorHandler
Этот middleware будем использовать в index.js
. Этот middleware должен быть последним и в нем не должно быть вызова next()
.
/* .......... */ import ErrorHandler from './middleware/ErrorHandler.js' const PORT = process.env.PORT || 5000 const app = express() app.use(cors()) app.use(express.json()) app.use('/api', router) // обработка ошибок app.use(ErrorHandler) const start = async () => { /* .......... */ } start()
Давайте проверим, как это работает. Допустим, что для получения списка всех товаров был отправлен некорректный HTTP-запрос.
import AppError from '../errors/AppError.js' class Product { async getAll(req, res, next) { if (true) { return next(AppError.badRequest('Этот запрос не удалось обработать')) } res.status(200).send('Список всех товаров') } /* .......... */ } export default new Product()
С помощью расширения REST Client для VS Code отправим запрос на получение списка товаров и посмотрим на ответ сервера:
- Магазин на JavaScript, часть 19 из 19. Редактирование характеристик и рефакторинг приложения
- Магазин на JavaScript, часть 18 из 19. Панель управления: редактирование категорий и брендов
- Магазин на JavaScript, часть 17 из 19. Панель управления: список заказов, категорий и брендов
- Магазин на JavaScript, часть 15 из 19. Работа с заказами на сервере, оформление заказа
- Магазин на JavaScript, часть 14 из 19. Кнопка «Назад», страница товара, корзина покупателя
- Магазин на JavaScript, часть 13 из 19. Хранилище каталога, компонент витрины, кнопка «Назад»
- Магазин на JavaScript, часть12 из 19. Запросы на сервер, состояние приложения, Signup и Login
Поиск: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • База данных • Интернет магазин • Каталог товаров • Корзина • Фреймворк