Далее мы идём улучшать нашу архитектуру.
Первым делом, запрос должен идти не напрямую в middleware, а через data transfer object, который хранит в себе данные в виде определённой структуры.
Внутри middleware будет находиться валидатор, который будет проверять dto на корректность переданных данных.
Так же мы введём такое понятие, как entity - это объект нашей бизнес-единицы, который сфокусирован на работе с самим объектом: создание объекта, преобразование и реализация внутренних методов (например, у пользователя есть метод хеширования его пароля).
Всё, что связано с бизнес-логикой, будет инкапсулировано в services и entity
079 Data transfer object
dto будет представлять из себя класс, который описывает, что мы получаем извне и передаём в контроллер
Сразу нужно сказать, что если наши классы очень похожи по принимаемым данным, то в данном случае мы могли бы сделать класс UserCredentional и от него экстендить эти два представленных класса. Однако объединять два dto - не нужно!
users > dto > user-register.dto.ts
users > dto > user-login.dto.ts
Ну и далее нужно упомянуть, что тип Request из express принимает в себя дженерик из трёх параметров, где третий представляет из себя body принимаемых данных
И теперь в методе login мы видим, что в запросе req.body сам body будет иметь тип данных UserLoginDto - то есть третий дженерик определяет тип body полученного запроса
users.controller.ts
И далее, чтобы увидеть ответ от сервера, нужно установить модуль, который будет серилиазовать полученный body в JSON
Ну и уже тут мы реализуем middleware, который будет принимать в себя все входящие запросы и парсить их в JSON
080 User entity
Entity - это бизнес единица, которая описывает какой-то бизнес объект в качестве какого-то класса, у которого могут быть свои методы и свойства и внутри него зашито описание и бизнес-логика.
Так же эта единица должна быть отделена от всей системы и не должна зависеть от остальных компонентов этой системы.
И вот представление реализации нашей отдельной сущности пользователя. Он максимально абстрагирован от остальных компонентов и не зависит от них.
users > user.entity.ts
Преобразуем функцию регистрации, где сразу проводим деструктуризацию параметра req, чтобы получить сразу body. Далее тут создаём нашего нового пользователя и передаём в него все нужные параметры, включая пароль.
users > users.controller.ts
И теперь по роуту регистрации мы можем получить нужные нам данные
081 Сервис users
Теперь нужно отделить роутинг (контроллер) и бизнес-логику (сервисы)
Работаем с сущностью
В сервисе у нас хранится только бизнес-логика: создаём entity, выставляем пароль, работаем с репозиторием
Создаём интерфейс нашей сущности
users.service.interface.ts
И тут представлена логика работы самой сущности. Она непосредственно имеет логику создания пользователя и так же работает с репозиторием (базой данных)
users.service.ts
Настраиваем DI
Чтобы связать нашу сущность, нужно добавить её в типы
types.ts
И забиндить в модуле контейнера, чтобы эта сущность хранилась в нём
main.ts
Взаимодейтсвуем с контроллером
Контроллер же у нас будет реализовывать роунтинг и контролировать входных и выходных данных.
Конкретно тут был внедрён UserService в конструктор. Так же реализована регистрация пользователя (контроль входных и выходных данных)
Результат
Как выглядит в действии:
082 Middleware для роутов
Создадим интерфейс самого посредника. Он будет выполнять ровно один метод, который ему предписан.
middleware.interface.ts
Наш контроллер роута будет принимать в себя (необязательно) массив посредников, которые будут выполняться до основной функции-хэндлера.
common > route.interface.ts
И далее в основном контроллере получаем массив посреднических функций, которому меняем контекст вызова на себя самого. В функции pipeline мы проверяем, если у нас имеются в принципе middlewares, то передаём в наш роут сначала эти функции-посредники, а уже только потом основную функцию
base.controller.ts
083 Валидация данных
Далее нужно реализовать middleware валидации данных, которые передаются в контроллер
Модуль для валидации данных
Модуль class-validator позволяет нам производить валидацию поступающих данных, декорируя их и производя валидацию внутри метода validate.
Тут ниже приведён пример валидации данных:
Модуль class-transformer позволяет нам перевести JSON данные в класс, чтобы заменить конструкцию присвоения на конструкцию трансформации
И теперь вместо такого ввода данных
Мы можем использовать уже заранее определённый класс:
Реализация валидации данных
Первым делом, нужно реализовать middleware, который будет осуществлять саму валидацию данных. Он будет в себя принимать класс для валидации данных. Затем в execute будет производён перевод полученного JSON в класс модулем class-transformer, который будет валидироваться методом validate из модуля class-validator
validate.middleware.ts
Затем в контроллере пользователя добавляем под запросы промежуточные обработчики
users.controller.ts
А производить проверку полученных данных будем в самом dto, где все полученные переменные будут валидироваться
user-login.dto.ts
Результат
При правильно отправленном запросе у нас будет успешное сообщение без ошибок