Машинопись

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 passport passport-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.

Хотите поддержать меня? Купи мне кофе.

Читать далее