├── README.md ├── apache-kafka ├── .gitignore └── docker-compose.yaml └── nest-api ├── .docker ├── entrypoint.sh └── postgres │ └── Dockerfile ├── .env ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── Dockerfile ├── README.md ├── docker-compose.yaml ├── nest-cli.json ├── package-lock.json ├── package.json ├── products.http ├── src ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── checkout │ ├── checkout.controller.spec.ts │ └── checkout.controller.ts ├── controllers │ └── product │ │ ├── product.controller.spec.ts │ │ └── product.controller.ts ├── exception-filters │ └── model-not-found.exception-filter.ts ├── main.ts ├── migrations │ └── 1611758114949-CreateProductsTable.ts ├── models │ └── product.model.ts ├── payment │ ├── payment.controller.spec.ts │ └── payment.controller.ts └── valida-alguma-coisa │ ├── valida-alguma-coisa.controller.spec.ts │ └── valida-alguma-coisa.controller.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json /README.md: -------------------------------------------------------------------------------- 1 | # Imersão Full Stack & FullCycle 2 | 3 | ## Descrição 4 | 5 | Repositório da live de Nest.js com Apache Kafka: [https://www.youtube.com/watch?v=9rIFuUUnmFE](https://www.youtube.com/watch?v=9rIFuUUnmFE) 6 | 7 | ## Rodar a aplicação 8 | 9 | ### Configurar host.docker.internal 10 | 11 | A comunicação entre o Nest.js e Apache Kafka está configurada para funcionar com o endereço **host.docker.internal**. 12 | 13 | Acrescente no seu /etc/hosts, para Windows o caminho é C:\Windows\system32\drivers\etc\hosts (Verifique se já não existe) 14 | 15 | ``` 16 | 127.0.0.1 host.docker.internal 17 | ``` 18 | 19 | ### Apache Kafka 20 | 21 | ``` 22 | cd apache-kafka 23 | docker-compose up 24 | 25 | # Antes de rodar o container novamnete faça: 26 | docker-compose down 27 | #Isto irá excluir os volumes do ZooKeeper e Apache Kafka 28 | ``` 29 | 30 | Acesse http://localhost9021 para manipular os tópicos do Kafka via Confluent Center 31 | 32 | ### Nest.js 33 | 34 | ``` 35 | cd nest-api 36 | docker-compose up 37 | 38 | # Antes de rodar o container novamnete faça: 39 | docker-compose down 40 | #Isto irá excluir os volumes do ZooKeeper e Apache Kafka 41 | ``` 42 | 43 | Acessar http://localhost:3000/checkout para testar o envio de mensagens 44 | 45 | ### Para Windows 46 | 47 | Lembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=gCUPP4E8Msc](https://www.youtube.com/watch?v=gCUPP4E8Msc) 48 | 49 | Siga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) 50 | -------------------------------------------------------------------------------- /apache-kafka/.gitignore: -------------------------------------------------------------------------------- 1 | .history/ 2 | -------------------------------------------------------------------------------- /apache-kafka/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | zookeeper: 4 | image: confluentinc/cp-zookeeper:latest 5 | environment: 6 | ZOOKEEPER_CLIENT_PORT: 2181 7 | 8 | kafka: 9 | image: confluentinc/cp-kafka:latest 10 | depends_on: 11 | - zookeeper 12 | ports: 13 | - "9092:9092" 14 | - "9094:9094" 15 | environment: 16 | KAFKA_BROKER_ID: 1 17 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 18 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 19 | KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL 20 | KAFKA_LISTENERS: INTERNAL://:9092,OUTSIDE://:9094 21 | KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:9092,OUTSIDE://host.docker.internal:9094 22 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,OUTSIDE:PLAINTEXT 23 | extra_hosts: 24 | - "host.docker.internal:172.17.0.1" 25 | 26 | control-center: 27 | image: confluentinc/cp-enterprise-control-center:6.0.1 28 | hostname: control-center 29 | depends_on: 30 | - kafka 31 | ports: 32 | - "9021:9021" 33 | environment: 34 | CONTROL_CENTER_BOOTSTRAP_SERVERS: 'kafka:9092' 35 | CONTROL_CENTER_REPLICATION_FACTOR: 1 36 | PORT: 9021 37 | -------------------------------------------------------------------------------- /nest-api/.docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm install 4 | npm run start:dev -------------------------------------------------------------------------------- /nest-api/.docker/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres 2 | 3 | RUN usermod -u 1000 postgres -------------------------------------------------------------------------------- /nest-api/.env: -------------------------------------------------------------------------------- 1 | TYPEORM_CONNECTION=postgres 2 | TYPEORM_HOST=db 3 | TYPEORM_USERNAME=postgres 4 | TYPEORM_PASSWORD=root 5 | TYPEORM_DATABASE=nest_api 6 | TYPEORM_PORT=5432 7 | TYPEORM_ENTITIES=src/**/*.model.ts 8 | TYPEORM_ENTITIES_DIR=src/models 9 | TYPEORM_MIGRATIONS=src/migrations/**/*.ts 10 | TYPEORM_MIGRATIONS_DIR=src/migrations -------------------------------------------------------------------------------- /nest-api/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/recommended', 10 | 'prettier/@typescript-eslint', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /nest-api/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | 36 | .docker/dbdata/ 37 | .history -------------------------------------------------------------------------------- /nest-api/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /nest-api/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#b61a3d", 4 | "activityBar.activeBorder": "#133808", 5 | "activityBar.background": "#b61a3d", 6 | "activityBar.foreground": "#e7e7e7", 7 | "activityBar.inactiveForeground": "#e7e7e799", 8 | "activityBarBadge.background": "#133808", 9 | "activityBarBadge.foreground": "#e7e7e7", 10 | "statusBar.background": "#b61a3d", 11 | "statusBar.foreground": "#e7e7e7", 12 | "statusBarItem.hoverBackground": "#e0234e" 13 | }, 14 | "peacock.remoteColor": "#e0234e" 15 | } -------------------------------------------------------------------------------- /nest-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.14.0-alpine3.11 2 | 3 | RUN apk add --no-cache bash 4 | 5 | RUN npm i -g @nestjs/cli@7.4.1 6 | 7 | USER node 8 | 9 | WORKDIR /home/node/app -------------------------------------------------------------------------------- /nest-api/README.md: -------------------------------------------------------------------------------- 1 | # Imersão Full Stack & FullCycle 2 | 3 | ## Descrição 4 | 5 | Repositório da live de Nest.js com API Rest: [https://www.youtube.com/watch?v=qE0jRojtx08](https://www.youtube.com/watch?v=qE0jRojtx08) 6 | 7 | ## Rodar a aplicação 8 | 9 | ``` 10 | docker-compose up 11 | ``` 12 | 13 | Acessar http://localhost:3000/products no browser ou de preferência no Postman ou similar. 14 | 15 | ### Para Windows 16 | 17 | Lembrar de instalar o WSL2 e Docker. Vejo o vídeo: [https://www.youtube.com/watch?v=gCUPP4E8Msc](https://www.youtube.com/watch?v=gCUPP4E8Msc) 18 | 19 | Siga o guia rápido de instalação: [https://github.com/codeedu/wsl2-docker-quickstart](https://github.com/codeedu/wsl2-docker-quickstart) 20 | -------------------------------------------------------------------------------- /nest-api/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | app: 6 | build: . 7 | entrypoint: ./.docker/entrypoint.sh 8 | container_name: esquenta-imersao-fullcycle-nest-api 9 | ports: 10 | - 3000:3000 11 | volumes: 12 | - .:/home/node/app 13 | extra_hosts: 14 | - "host.docker.internal:172.17.0.1" 15 | 16 | db: 17 | build: .docker/postgres 18 | restart: always 19 | tty: true 20 | volumes: 21 | - .docker/dbdata:/var/lib/postgresql/data 22 | environment: 23 | - POSTGRES_PASSWORD=root 24 | - POSTGRES_DB=nest_api 25 | 26 | pgadmin: 27 | image: dpage/pgadmin4 28 | tty: true 29 | environment: 30 | - PGADMIN_DEFAULT_EMAIL=admin@user.com 31 | - PGADMIN_DEFAULT_PASSWORD=123456 32 | ports: 33 | - "9000:80" 34 | depends_on: 35 | - db -------------------------------------------------------------------------------- /nest-api/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /nest-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nest-api", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json", 22 | "typeorm": "ts-node ./node_modules/typeorm/cli.js" 23 | }, 24 | "dependencies": { 25 | "@nestjs/common": "^7.5.1", 26 | "@nestjs/config": "^0.6.2", 27 | "@nestjs/core": "^7.5.1", 28 | "@nestjs/microservices": "^7.6.7", 29 | "@nestjs/platform-express": "^7.5.1", 30 | "@nestjs/typeorm": "^7.1.5", 31 | "kafkajs": "^1.15.0", 32 | "pg": "^8.5.1", 33 | "reflect-metadata": "^0.1.13", 34 | "rimraf": "^3.0.2", 35 | "rxjs": "^6.6.3", 36 | "typeorm": "^0.2.30" 37 | }, 38 | "devDependencies": { 39 | "@nestjs/cli": "^7.5.1", 40 | "@nestjs/schematics": "^7.1.3", 41 | "@nestjs/testing": "^7.5.1", 42 | "@types/express": "^4.17.8", 43 | "@types/jest": "^26.0.15", 44 | "@types/node": "^14.14.6", 45 | "@types/supertest": "^2.0.10", 46 | "@typescript-eslint/eslint-plugin": "^4.6.1", 47 | "@typescript-eslint/parser": "^4.6.1", 48 | "eslint": "^7.12.1", 49 | "eslint-config-prettier": "7.2.0", 50 | "eslint-plugin-prettier": "^3.1.4", 51 | "jest": "^26.6.3", 52 | "prettier": "^2.1.2", 53 | "supertest": "^6.0.0", 54 | "ts-jest": "^26.4.3", 55 | "ts-loader": "^8.0.8", 56 | "ts-node": "^9.0.0", 57 | "tsconfig-paths": "^3.9.0", 58 | "typescript": "^4.0.5" 59 | }, 60 | "jest": { 61 | "moduleFileExtensions": [ 62 | "js", 63 | "json", 64 | "ts" 65 | ], 66 | "rootDir": "src", 67 | "testRegex": ".*\\.spec\\.ts$", 68 | "transform": { 69 | "^.+\\.(t|j)s$": "ts-jest" 70 | }, 71 | "collectCoverageFrom": [ 72 | "**/*.(t|j)s" 73 | ], 74 | "coverageDirectory": "../coverage", 75 | "testEnvironment": "node" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /nest-api/products.http: -------------------------------------------------------------------------------- 1 | ### 2 | POST http://localhost:3000/products 3 | Content-Type: application/json 4 | 5 | { 6 | "name": "produto teste", 7 | "price": 10.12 8 | } 9 | 10 | ### 11 | GET http://localhost:3000/products/0 12 | 13 | 14 | ### 15 | GET http://localhost:3000/products 16 | 17 | ### 18 | DELETE http://localhost:3000/products/5 19 | 20 | ### 21 | PUT http://localhost:3000/products/4 22 | Content-Type: application/json 23 | 24 | { 25 | "name": "produto alterado", 26 | "price": 10.20 27 | } -------------------------------------------------------------------------------- /nest-api/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /nest-api/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Post, Put } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller('app') 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get('test') 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } -------------------------------------------------------------------------------- /nest-api/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | import { AppController } from './app.controller'; 5 | import { AppService } from './app.service'; 6 | import { Product } from './models/product.model'; 7 | import { ProductController } from './controllers/product/product.controller'; 8 | import { CheckoutController } from './checkout/checkout.controller'; 9 | import { ClientsModule, Transport } from '@nestjs/microservices'; 10 | import { PaymentController } from './payment/payment.controller'; 11 | import { ValidaAlgumaCoisaController } from './valida-alguma-coisa/valida-alguma-coisa.controller'; 12 | 13 | @Module({ 14 | imports: [ 15 | ConfigModule.forRoot(), 16 | TypeOrmModule.forRoot({ 17 | type: process.env.TYPEORM_CONNECTION as any, 18 | host: process.env.TYPEORM_HOST, 19 | port: parseInt(process.env.TYPEORM_PORT), 20 | username: process.env.TYPEORM_USERNAME, 21 | password: process.env.TYPEORM_PASSWORD, 22 | database: process.env.TYPEORM_DATABASE, 23 | entities: [Product], 24 | }), 25 | TypeOrmModule.forFeature([Product]), 26 | ClientsModule.register([ 27 | { 28 | name: 'KAFKA_SERVICE', 29 | transport: Transport.KAFKA, 30 | options: { 31 | client: { 32 | brokers: ['host.docker.internal:9094'], 33 | }, 34 | consumer: { 35 | groupId: 'my-consumer-' + Math.random(), 36 | }, 37 | }, 38 | }, 39 | ]), 40 | ], 41 | controllers: [AppController, ProductController, CheckoutController, PaymentController, ValidaAlgumaCoisaController], 42 | providers: [AppService], 43 | }) 44 | export class AppModule {} 45 | -------------------------------------------------------------------------------- /nest-api/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /nest-api/src/checkout/checkout.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { CheckoutController } from './checkout.controller'; 3 | 4 | describe('CheckoutController', () => { 5 | let controller: CheckoutController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [CheckoutController], 10 | }).compile(); 11 | 12 | controller = module.get(CheckoutController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /nest-api/src/checkout/checkout.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject, OnModuleInit } from '@nestjs/common'; 2 | import { ClientKafka } from '@nestjs/microservices'; 3 | import { Producer } from '@nestjs/microservices/external/kafka.interface'; 4 | 5 | @Controller('checkout') 6 | export class CheckoutController implements OnModuleInit { 7 | private kafkaProducer: Producer; 8 | 9 | constructor( 10 | @Inject('KAFKA_SERVICE') 11 | private clientKafka: ClientKafka, 12 | ) {} 13 | 14 | async onModuleInit() { 15 | this.kafkaProducer = await this.clientKafka.connect(); 16 | } 17 | 18 | @Get() 19 | async checkout() { 20 | const result = await this.kafkaProducer.send({ 21 | topic: 'pagamentos', 22 | messages: [ 23 | {key: Math.random()+"", value: JSON.stringify({order: 1000, client: 'FullCycle'}) } 24 | ] 25 | }); 26 | 27 | //console.log(result); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nest-api/src/controllers/product/product.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { ProductController } from './product.controller'; 3 | 4 | describe('ProductController', () => { 5 | let controller: ProductController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [ProductController], 10 | }).compile(); 11 | 12 | controller = module.get(ProductController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /nest-api/src/controllers/product/product.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | Delete, 5 | Get, 6 | HttpCode, 7 | Param, 8 | Post, 9 | Put, 10 | } from '@nestjs/common'; 11 | import { InjectRepository } from '@nestjs/typeorm'; 12 | import { Product } from 'src/models/product.model'; 13 | import { Repository } from 'typeorm'; 14 | 15 | @Controller('products') 16 | export class ProductController { 17 | constructor( 18 | @InjectRepository(Product) 19 | private productRepo: Repository, 20 | ) {} 21 | 22 | @Get() 23 | index() { 24 | return this.productRepo.find(); 25 | } 26 | 27 | @Get(':id') 28 | show(@Param('id') id: string) { 29 | return this.productRepo.findOneOrFail(id); 30 | } 31 | 32 | @Post() 33 | store(@Body() body) { 34 | const product = this.productRepo.create(body); 35 | return this.productRepo.save(product); 36 | } 37 | 38 | @Put(':id') 39 | async update(@Param('id') id: string, @Body() body) { 40 | await this.productRepo.findOneOrFail(id); 41 | this.productRepo.update({ id: +id }, body); 42 | return await this.productRepo.findOne(id); 43 | } 44 | 45 | @Delete(':id') 46 | @HttpCode(204) 47 | async delete(@Param('id') id: string) { 48 | await this.productRepo.findOneOrFail(id); 49 | this.productRepo.delete(id); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /nest-api/src/exception-filters/model-not-found.exception-filter.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentsHost, Catch, ExceptionFilter } from "@nestjs/common"; 2 | import {EntityNotFoundError} from 'typeorm/error/EntityNotFoundError'; 3 | import {Response} from 'express'; 4 | 5 | @Catch(EntityNotFoundError) 6 | export class ModelNotFoundExceptionFilter implements ExceptionFilter{ 7 | catch(exception: EntityNotFoundError, host: ArgumentsHost){ 8 | const context = host.switchToHttp(); 9 | const response = context.getResponse(); 10 | return response.status(404).json({ 11 | error: { 12 | error: 'Not Found', 13 | message: exception.message 14 | } 15 | }) 16 | } 17 | } -------------------------------------------------------------------------------- /nest-api/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { Transport } from '@nestjs/microservices'; 3 | import { AppModule } from './app.module'; 4 | import { ModelNotFoundExceptionFilter } from './exception-filters/model-not-found.exception-filter'; 5 | 6 | async function bootstrap() { 7 | const app = await NestFactory.create(AppModule, { cors: true }); 8 | app.connectMicroservice({ 9 | transport: Transport.KAFKA, 10 | options: { 11 | client: { 12 | brokers: ['host.docker.internal:9094'], 13 | }, 14 | consumer: { 15 | groupId: 'my-consumer-' + Math.random(), 16 | }, 17 | }, 18 | }); 19 | 20 | app.useGlobalFilters(new ModelNotFoundExceptionFilter()); 21 | await app.startAllMicroservicesAsync(); 22 | await app.listen(3000); 23 | } 24 | bootstrap(); 25 | 26 | -------------------------------------------------------------------------------- /nest-api/src/migrations/1611758114949-CreateProductsTable.ts: -------------------------------------------------------------------------------- 1 | import {MigrationInterface, QueryRunner, Table} from "typeorm"; 2 | 3 | export class CreateProductsTable1611758114949 implements MigrationInterface { 4 | 5 | public async up(queryRunner: QueryRunner): Promise { 6 | await queryRunner.createTable( 7 | new Table({ 8 | name: 'products', 9 | columns: [ 10 | { 11 | name: 'id', 12 | type: 'int', 13 | isPrimary: true, 14 | isGenerated: true, 15 | generationStrategy: 'increment' 16 | }, 17 | { 18 | name: 'name', 19 | type: 'varchar' 20 | }, 21 | { 22 | name: 'price', 23 | type: 'double precision' 24 | }, 25 | { 26 | name: 'created_at', 27 | type: 'timestamp', 28 | default: 'CURRENT_TIMESTAMP' 29 | } 30 | ] 31 | }) 32 | ) 33 | } 34 | 35 | public async down(queryRunner: QueryRunner): Promise { 36 | await queryRunner.dropTable('products'); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /nest-api/src/models/product.model.ts: -------------------------------------------------------------------------------- 1 | import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn} from "typeorm"; 2 | 3 | @Entity({name: 'products'}) 4 | export class Product { 5 | @PrimaryGeneratedColumn() 6 | id: number; 7 | 8 | @Column() 9 | name: string; 10 | 11 | @Column() 12 | price: number; 13 | 14 | @CreateDateColumn({type: 'timestamp'}) 15 | created_at: Date; 16 | } 17 | -------------------------------------------------------------------------------- /nest-api/src/payment/payment.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { PaymentController } from './payment.controller'; 3 | 4 | describe('PaymentController', () => { 5 | let controller: PaymentController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [PaymentController], 10 | }).compile(); 11 | 12 | controller = module.get(PaymentController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /nest-api/src/payment/payment.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Inject, OnModuleInit } from '@nestjs/common'; 2 | import { ClientKafka, MessagePattern, Payload } from '@nestjs/microservices'; 3 | 4 | //rxjs 5 | //request-reply | request-response 6 | @Controller() 7 | export class PaymentController implements OnModuleInit { 8 | constructor( 9 | @Inject('KAFKA_SERVICE') 10 | private clientKafka: ClientKafka, 11 | ) {} 12 | 13 | async onModuleInit() { 14 | this.clientKafka.subscribeToResponseOf('valida_alguma_coisa'); 15 | } 16 | 17 | @MessagePattern('pagamentos') 18 | consumePayment(@Payload() message) { 19 | console.log(message.value); 20 | this.clientKafka.send( 21 | 'valida_alguma_coisa', 22 | JSON.stringify({ key1: 'val1' }), 23 | ).subscribe(reply => console.log(reply)); 24 | 25 | 26 | } 27 | } 28 | 29 | 30 | //#1 - Checkout -> envia mensagem -> Pagamentos 31 | //#2 - Pagamento recebe a mensagem e envia uma nova mensagem para outra aplicacao 32 | //#3 - Pagamento fica esperando que a outra aplicação confirme que recebeu mensagem 33 | -------------------------------------------------------------------------------- /nest-api/src/valida-alguma-coisa/valida-alguma-coisa.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { ValidaAlgumaCoisaController } from './valida-alguma-coisa.controller'; 3 | 4 | describe('ValidaAlgumaCoisaController', () => { 5 | let controller: ValidaAlgumaCoisaController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [ValidaAlgumaCoisaController], 10 | }).compile(); 11 | 12 | controller = module.get(ValidaAlgumaCoisaController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /nest-api/src/valida-alguma-coisa/valida-alguma-coisa.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common'; 2 | import { MessagePattern, Payload } from '@nestjs/microservices'; 3 | 4 | @Controller() 5 | export class ValidaAlgumaCoisaController { 6 | @MessagePattern('valida_alguma_coisa') 7 | validaAlgumaCoisa(@Payload() message){ 8 | console.log(message.value); 9 | return { 10 | respondi: 'respondi' 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /nest-api/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /nest-api/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /nest-api/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /nest-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true 14 | }, 15 | "include": ["src"], 16 | "exclude": [ 17 | "node_modules", 18 | "dist", 19 | ".docker" 20 | ] 21 | } 22 | --------------------------------------------------------------------------------