Машинопись
NestJS: микросервисы с gRPC, шлюзом API и аутентификацией — часть 2/2
Вторая часть приложения NestJS с gRPC, шлюзом API, аутентификацией и проверкой
Добро пожаловать во вторую часть моего пошагового руководства по разработке нескольких микросервисов с помощью NestJS плюс шлюз API и аутентификация.
Так как первая часть была довольно тяжелой, давайте не будем терять много времени!
На случай, если вы не читали часть 1:
Часть 2 начинается здесь!
Служба аутентификации (grpc-nest-auth-svc)
После длительной подготовки путем написания кода шлюза API, настройки баз данных и предоставления наших прото-файлов в качестве общего репозитория мы, наконец, начинаем с нашей самой первой микрослужбы.
Гитхаб: https://github.com/hellokvn/grpc-nest-auth-svc
Во-первых, нам нужно открыть проект в нашем редакторе кода, поэтому вернитесь в свой терминал в каталог, где мы храним наши проекты.
$ cd grpc-nest-auth-svc $ code .
Установка зависимостей
Давайте установим некоторые зависимости, которые нам понадобятся.
$ npm i @nestjs/microservices @nestjs/typeorm@nestjs/jwt @nestjs/passport
passportpassport-jwt
typeorm pg class-transformer class-validator bcryptjs $ npm i -D @types/node@types/passport-jwt
ts-proto
Структура проекта
Как обычно в моих руководствах, я продолжу создание окончательной структуры папок и файлов. Для простоты мы просто выберем здесь один модуль, который будет называться auth
.
$ nest g mo auth && nest g co auth --no-spec $ mkdir src/auth/filter && mkdir src/auth/service && mkdir src/auth/strategy $ touch src/auth/filter/http-exception.filter.ts $ touch src/auth/service/auth.service.ts $ touch src/auth/service/jwt.service.ts $ touch src/auth/strategy/jwt.strategy.ts $ touch src/auth/auth.dto.ts $ touch src/auth/auth.entity.ts
Добавление скриптов
Кроме того, нам нужно добавить несколько сценариев в наш package.json
для создания файлов protobuf на основе общего проекта proto, который мы только что завершили. Подобно тому, что мы сделали в шлюзе API.
Давайте просто добавим эти 5 строк кода в свойство scripts
нашего файла package.json
.
Замените YOUR_USERNAME своим именем пользователя Github.
Давайте запустим эти скрипты!
$ npm run proto:install && npm run proto:auth
Итак, после этих шагов наш проект должен выглядеть так:
Теперь давайте начнем кодировать.
Фильтр исключений HTTP
Поскольку мы собираемся использовать файлы Data-Transfer-Object для проверки нашей полезной нагрузки, нам нужно перехватывать исключения HTTP, потому что пакет class-validator, который мы собираемся использовать, генерирует исключения HTTP в случае, если полезная нагрузка запроса является недействительным. Поскольку мы не хотим генерировать исключения HTTP с нашего сервера gRPC, мы перехватываем эти исключения и превращаем их в обычный ответ gRPC.
Давайте добавим немного кода в src/auth/filter/http-exception.filter.ts
Аутентификация DTO/проверка
Давайте добавим немного кода вsrc/auth/auth.dto.ts
Объект аутентификации
Давайте добавим немного кода вsrc/auth/auth.entity.ts
JWT-сервис
Давайте добавим немного кода вsrc/auth/service/jwt.service.ts
Стратегия JWT
Давайте добавим немного кода вsrc/auth/strategy/jwt.strategy.ts
Служба аутентификации
Давайте добавим немного кода вsrc/auth/service/auth.service.ts
Контроллер авторизации
Давайте изменим src/auth/auth.controller.ts
с
to
Модуль авторизации
Давайте изменим src/auth/auth.module.ts
с
to
Модуль приложения
Давайте изменим src/app.module.ts
с
to
Начальная загрузка
Давайте изменим main.ts
с
to
Запускаем наш микросервис
$ npm run start:dev
Большой! Все работает так, как ожидалось. Теперь мы закончили с нашим микросервисом аутентификации, осталось только 2 микросервиса. Поскольку микрослужба заказов в некотором роде зависит от микрослужбы продуктов, далее мы собираемся сделать микрослужбу продуктов.
Оба микросервиса будет намного проще разрабатывать, как и их конечные точки на шлюзе API, поскольку им просто нужно обрабатывать входящие данные.
Сервис продукта (grpc-nest-product-svc)
Гитхаб: https://github.com/hellokvn/grpc-nest-product-svc
После выполнения этой команды мы открываем проект grp-nest-product-svc
в нашем редакторе кода.
$ cd grpc-nest-product-svc $ code .
Установка зависимостей
Давайте установим некоторые зависимости, которые нам понадобятся.
$ npm i @nestjs/microservices @grpc/grpc-js @grpc/proto-loader @nestjs/typeorm typeorm pg class-transformer class-validator $ npm i -D @types/node ts-proto
Структура проекта
Как обычно в моих руководствах, я продолжу создание окончательной структуры папок и файлов. Для простоты мы просто выберем здесь один модуль, который будет называться product
.
$ nest g mo product && nest g co product --no-spec && nest g s product --no-spec $ mkdir src/product/entity $ touch src/product/product.dto.ts $ touch src/product/entity/product.entity.ts $ touch src/product/entity/stock-decrease-log.entity.ts
Добавление скриптов
Кроме того, нам нужно добавить несколько скриптов в наш package.json
для создания файлов protobuf на основе общего проекта proto, который мы только что завершили. Подобно тому, что мы сделали в шлюзе API.
Давайте просто добавим эти 2 строки кода в свойство scripts
нашего файла package.json
.
Замените YOUR_USERNAME своим именем пользователя Github.
Давайте запустим эти скрипты!
$ npm run proto:install && npm run proto:product
Итак, после этих шагов наш проект должен выглядеть так:
Теперь пришло время кодировать.
Продукт
Во-первых, мы создаем нашу сущность Product.
Давайте добавим немного кода в src/product/entity/product.entity.ts
Объект StockDecreaseLog
Кроме того, мы должны создать нашу сущность StockDecreaseLog. Здесь мы сохраняем каждое действие по уменьшению, связанное с идентификатором заказа и идентификатором продукта. Это потому, что мы хотим предотвратить любое многократное снижение из-за создания одного единственного заказа, вызванного непредсказуемыми ошибками.
Давайте добавим немного кода в src/product/entity/stock-decrease-log.entity.ts
DTO продукта/проверка
Для проверки мы создаем 3 DTO, реализуя интерфейс каждой конечной точки.
Давайте добавим немного кода в src/product/product.dto.ts
Продукт Сервис
Поскольку у нас есть 3 конечных точки, нам нужно обслуживать 3 службы для каждой конечной точки. Вы очень быстро поймете, что происходит, так как их имена говорят сами за себя.
Давайте изменим src/product/product.service.ts
с
to
В строке 49 мы проверим, уменьшался ли товар уже один раз на один конкретный заказ. Это по причинам идемпотентности. Представьте, что мы дважды вызываем функцию понижения запаса для одного и того же заказа из-за какой-то ошибки, а затем у нас неверный запас товара. Мы собираемся предотвратить это, привязав идентификатор заказа к этому методу. Так что даже если вызвать этот метод случайно дважды, запас будет правильным.
Что такое идемпотентность?
Идемпотентность — это свойство, гарантирующее, что повторные вызовы одной и той же операции не приведут к каким-либо изменениям состояния службы или дополнительным побочным эффектам.
Контроллер продукта
Кроме того, каждой конечной точке нужен метод внутри нашего контроллера.
Давайте изменим src/product/product.controller.ts
с
to
Модуль продукта
Теперь нам нужно просто добавить объект продукта в наш модуль, так как мы собираемся использовать его внутри сервиса продукта.
Давайте изменим src/product/product.module.ts
с
to
Модуль приложения
В этом микросервисе нам также нужно подключение к базе данных.
Давайте изменим src/app.module.ts
с
to
Начальная загрузка
И последнее, но не менее важное: нам нужно зарегистрировать наш микросервис на порту 50053.
Давайте изменим main.ts
с
to
Теперь мы можем запустить наш продуктовый микросервис.
$ npm run start:dev
Поздравляем! Наша продуктовая микрослужба завершена.
Служба заказов (grpc-nest-order-svc)
Гитхаб: https://github.com/hellokvn/grpc-nest-order-svc
Наконец-то мы добрались до самого последнего микросервиса. Я буду максимально простым, так что оставайтесь со мной в самом последнем раунде. Опять же, на вашем терминале вернитесь в каталог, где мы храним все наши проекты для этого руководства, затем:
$ cd grpc-nest-order-svc $ code .
Установка зависимостей
Давайте установим некоторые зависимости, которые нам понадобятся.
$ npm i @nestjs/microservices @grpc/grpc-js @grpc/proto-loader @nestjs/typeorm typeorm pg class-transformer class-validator $ npm i -D @types/node ts-proto
Структура проекта
Давайте создадим бережливую структуру проекта.
$ nest g mo order && nest g co order --no-spec && nest g s order --no-spec $ mkdir src/order/proto $ touch src/order/order.dto.ts $ touch src/order/order.entity.ts
Добавление скриптов
Кроме того, нам нужно добавить несколько сценариев в наш package.json
для создания файлов protobuf на основе только что завершенного общего проекта proto. Подобно тому, что мы сделали в шлюзе API.
Давайте просто добавим эти 4 строки кода в свойство scripts
нашего файла package.json
.
Замените YOUR_USERNAME своим именем пользователя Github.
Давайте запустим эти скрипты!
$ npm run proto:install && npm run proto:all
Итак, после этих шагов наш проект должен выглядеть так:
Большой! Теперь давайте кодировать.
Объект заказа
Как обычно, мы начинаем с нашей сущности. Помните, что для простоты в каждом заказе может храниться только 1 продукт. Цена будет равна цене товара на момент заказа.
Давайте добавим немного кода в src/order/order.entity.ts
Заказать DTO / Проверка
Для проверки мы создаем класс, который реализует интерфейс нашего сгенерированного файла protobuf. Количество должно быть не менее 1, я думаю, это самоочевидно.
Давайте добавим немного кода в src/order/order.dto.ts
Заказать услугу
Служба заказов немного отличается, потому что мы впервые вызываем микрослужбу из другой микрослужбы. Мы собираемся дважды вызвать микросервис продукта. Сначала мы проверим, существует ли продукт, а затем уменьшим запас этого продукта, чтобы создать заказ.
Давайте изменим src/order/order.service.ts
с
to
Контроллер заказов
На нашем последнем контроллере нам нужно создать метод для получения входящего запроса от шлюза API.
Давайте изменим src/order/order.controller.ts
с
to
Модуль заказа
Поскольку мы собираемся подключаться к Product Microservice, нам нужно зарегистрировать клиента.
Теперь давайте изменим src/order/order.module.ts
с
to
Модуль приложения
И снова нам нужно подключиться к базе данных, которую мы создали в первой части этой статьи.
Теперь давайте изменим src/app.module.ts
с
to
Начальная загрузка
И в самый последний раз нам нужно инициализировать наш микросервис в NestJS.
Давайте изменим main.ts
с
to
Теперь мы можем запустить этот микросервис.
$ npm run start:dev
Тестирование
Теперь давайте проверим наши конечные точки. Имейте в виду, что вам нужно запустить все 3 микросервиса, а также ваш шлюз API. Вы можете использовать такие программы, как Postman, Insomnia или просто с помощью команд CURL в вашем терминале.
Вы создали документ Insomnia со всеми конечными точками, которые вы можете импортировать. Здесь — файл JSON.
Регистрация пользователя
$ curl -X POST http://localhost:3000/auth/register -H "Content-Type: application/json" -d '{"email": "[email protected]", "password": "12345678"}' Server Response: { "status": 201 }
Логин пользователя
$ curl -X PUT http://localhost:3000/auth/login -H "Content-Type: application/json" -d '{"email": "[email protected]", "password": "12345678"}' Server Response: { "status": 200, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJoZWxsb2tldmludm9nZWxAZ21haWwuY29tIiwiaWF0IjoxNjQ3NTMzMjczLCJleHAiOjE2NzkwNjkyNzN9.w14jPT72_sfbdPIPXxEmSdopn8TXS-EDMJ3HalXT9Kw" }
Создать продукт
$ curl -X POST http://localhost:3000/product -H "Content-Type: application/json" -d '{"name": "Test A", "sku": "A00001", "price": 100, "stock": 5}' Server Response: { "status": 200, "id": 1 }
Создать заказ
$ curl -X POST http://localhost:3000/order -H "Content-Type: application/json" -d '{"productId": 1, "quantity": 1}' Server Response: { "status": 200, "id": 1 }
Спасибо, что прочитали мою статью. Надеюсь, вы смогли узнать что-то новое и понять идею gRPC. Дайте знать, если у вас появятся вопросы.
Ваше здоровье!
Надеюсь, вам понравилось это читать. Если вы хотите поддержать меня как писателя, рассмотрите возможность подписки стать участником Medium. Всего 5 долларов в месяц, и вы получаете неограниченный доступ к Medium.
Хотите поддержать меня? Купи мне кофе.