├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── aspnetcore-api ├── .vs │ └── aspnetcore-api │ │ ├── DesignTimeBuild │ │ └── .dtbcache.v2 │ │ ├── project-colors.json │ │ └── v17 │ │ ├── .futdcache.v1 │ │ └── .suo ├── Program.cs ├── Properties │ └── launchSettings.json ├── Protos │ └── greet.proto ├── Services │ └── GreeterService.cs ├── appsettings.Development.json ├── appsettings.json ├── aspnetcore-api.csproj ├── aspnetcore-api.sln └── images │ └── greetservicetesting.png ├── gRPC microservice example diagram.png ├── grpc-nest-api-gateway ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── images │ ├── bookservicetesting.png │ └── greetservicetesting.png ├── nest-cli.json ├── package-lock.json ├── package.json ├── src │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── book │ │ ├── book.controller.ts │ │ ├── book.module.ts │ │ └── book.pb.ts │ ├── greet │ │ ├── greet.controller.ts │ │ ├── greet.module.ts │ │ └── greet.pb.ts │ └── main.ts ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json ├── grpc-nest-book-svc ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── images │ └── bookservicetesting.png ├── nest-cli.json ├── package-lock.json ├── package.json ├── src │ ├── book.controller.ts │ ├── book.module.ts │ ├── book.service.ts │ ├── books.mock.ts │ └── main.ts ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json ├── grpc-nest-proto ├── build │ └── proto │ │ ├── book.pb.ts │ │ └── greet.pb.ts ├── compile.proto.sh ├── package-lock.json ├── package.json └── proto │ ├── book.proto │ └── greet.proto └── readme.md /.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 | grpc-nest-proto/node_modules/* 36 | protoc-3.20.0-win64/* 37 | .vscode/launch.json 38 | aspnetcore-api/bin/* 39 | aspnetcore-api/obj/* 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/aspnetcore-api/aspnetcore-api.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/aspnetcore-api/aspnetcore-api.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "--project", 36 | "${workspaceFolder}/aspnetcore-api/aspnetcore-api.csproj" 37 | ], 38 | "problemMatcher": "$msCompile" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /aspnetcore-api/.vs/aspnetcore-api/DesignTimeBuild/.dtbcache.v2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/aspnetcore-api/.vs/aspnetcore-api/DesignTimeBuild/.dtbcache.v2 -------------------------------------------------------------------------------- /aspnetcore-api/.vs/aspnetcore-api/project-colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": 1, 3 | "ProjectMap": { 4 | "8b599c74-5a36-4b62-9358-380a66b131b1": { 5 | "ProjectGuid": "8b599c74-5a36-4b62-9358-380a66b131b1", 6 | "DisplayName": "aspnetcore-api", 7 | "ColorIndex": 0 8 | } 9 | }, 10 | "NextColorIndex": 1 11 | } -------------------------------------------------------------------------------- /aspnetcore-api/.vs/aspnetcore-api/v17/.futdcache.v1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/aspnetcore-api/.vs/aspnetcore-api/v17/.futdcache.v1 -------------------------------------------------------------------------------- /aspnetcore-api/.vs/aspnetcore-api/v17/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/aspnetcore-api/.vs/aspnetcore-api/v17/.suo -------------------------------------------------------------------------------- /aspnetcore-api/Program.cs: -------------------------------------------------------------------------------- 1 | using aspnetcore_api.Services; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Additional configuration is required to successfully run gRPC on macOS. 6 | // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 7 | 8 | // Add services to the container. 9 | builder.Services.AddGrpc(); 10 | 11 | var app = builder.Build(); 12 | 13 | // Configure the HTTP request pipeline. 14 | app.MapGrpcService(); 15 | app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); 16 | 17 | app.Run(); 18 | -------------------------------------------------------------------------------- /aspnetcore-api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "aspnetcore-api": { 4 | "commandName": "Project", 5 | "dotnetRunMessages": true, 6 | "launchBrowser": false, 7 | "applicationUrl": "http://localhost:5284;https://localhost:7035", 8 | "environmentVariables": { 9 | "ASPNETCORE_ENVIRONMENT": "Development" 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /aspnetcore-api/Protos/greet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option csharp_namespace = "aspnetcore_api"; 4 | 5 | package greet; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply); 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings. 19 | message HelloReply { 20 | string message = 1; 21 | } 22 | -------------------------------------------------------------------------------- /aspnetcore-api/Services/GreeterService.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | using aspnetcore_api; 3 | 4 | namespace aspnetcore_api.Services; 5 | 6 | public class GreeterService : Greeter.GreeterBase 7 | { 8 | private readonly ILogger _logger; 9 | public GreeterService(ILogger logger) 10 | { 11 | _logger = logger; 12 | } 13 | 14 | public override Task SayHello(HelloRequest request, ServerCallContext context) 15 | { 16 | return Task.FromResult(new HelloReply 17 | { 18 | Message = "Hello " + request.Name 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /aspnetcore-api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /aspnetcore-api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "Kestrel": { 10 | "EndpointDefaults": { 11 | "Protocols": "Http2" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /aspnetcore-api/aspnetcore-api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /aspnetcore-api/aspnetcore-api.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32126.317 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aspnetcore-api", "aspnetcore-api.csproj", "{8B599C74-5A36-4B62-9358-380A66B131B1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8B599C74-5A36-4B62-9358-380A66B131B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {8B599C74-5A36-4B62-9358-380A66B131B1}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {8B599C74-5A36-4B62-9358-380A66B131B1}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {8B599C74-5A36-4B62-9358-380A66B131B1}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {452AA265-106C-4D4B-AA9E-1B482E3F0E16} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /aspnetcore-api/images/greetservicetesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/aspnetcore-api/images/greetservicetesting.png -------------------------------------------------------------------------------- /gRPC microservice example diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/gRPC microservice example diagram.png -------------------------------------------------------------------------------- /grpc-nest-api-gateway/.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 | 'plugin:prettier/recommended', 11 | ], 12 | root: true, 13 | env: { 14 | node: true, 15 | jest: true, 16 | }, 17 | ignorePatterns: ['.eslintrc.js'], 18 | rules: { 19 | '@typescript-eslint/interface-name-prefix': 'off', 20 | '@typescript-eslint/explicit-function-return-type': 'off', 21 | '@typescript-eslint/explicit-module-boundary-types': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json -------------------------------------------------------------------------------- /grpc-nest-api-gateway/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /grpc-nest-api-gateway/README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 6 | [circleci-url]: https://circleci.com/gh/nestjs/nest 7 | 8 |

A progressive Node.js framework for building efficient and scalable server-side applications.

9 |

10 | NPM Version 11 | Package License 12 | NPM Downloads 13 | CircleCI 14 | Coverage 15 | Discord 16 | Backers on Open Collective 17 | Sponsors on Open Collective 18 | 19 | Support us 20 | 21 |

22 | 24 | 25 | ## Description 26 | 27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 28 | 29 | ## Installation 30 | 31 | ```bash 32 | $ npm install 33 | ``` 34 | 35 | ## Running the app 36 | 37 | ```bash 38 | # development 39 | $ npm run start 40 | 41 | # watch mode 42 | $ npm run start:dev 43 | 44 | # production mode 45 | $ npm run start:prod 46 | ``` 47 | 48 | ## Test 49 | 50 | ```bash 51 | # unit tests 52 | $ npm run test 53 | 54 | # e2e tests 55 | $ npm run test:e2e 56 | 57 | # test coverage 58 | $ npm run test:cov 59 | ``` 60 | 61 | ## Support 62 | 63 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 64 | 65 | ## Stay in touch 66 | 67 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 68 | - Website - [https://nestjs.com](https://nestjs.com/) 69 | - Twitter - [@nestframework](https://twitter.com/nestframework) 70 | 71 | ## License 72 | 73 | Nest is [MIT licensed](LICENSE). 74 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/images/bookservicetesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/grpc-nest-api-gateway/images/bookservicetesting.png -------------------------------------------------------------------------------- /grpc-nest-api-gateway/images/greetservicetesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/grpc-nest-api-gateway/images/greetservicetesting.png -------------------------------------------------------------------------------- /grpc-nest-api-gateway/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "assets": ["**/*.proto"], 7 | "watchAssets": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grpc-nest-api-gateway", 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 | "proto:install": "npm i git+https://github.com/YOUR_USERNAME/grpc-nest-proto.git", 23 | "proto:book": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/book/ ../grpc-nest-proto/proto/book.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 24 | "proto:magazine": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/magazine/ ../grpc-nest-proto/proto/magazine.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 25 | "proto:all": "npm run proto:book && npm run proto:magazine" 26 | }, 27 | "dependencies": { 28 | "@grpc/grpc-js": "^1.6.2", 29 | "@grpc/proto-loader": "^0.6.9", 30 | "@nestjs/common": "^8.0.0", 31 | "@nestjs/core": "^8.0.0", 32 | "@nestjs/microservices": "^8.4.3", 33 | "@nestjs/platform-express": "^8.0.0", 34 | "reflect-metadata": "^0.1.13", 35 | "rimraf": "^3.0.2", 36 | "rxjs": "^7.2.0" 37 | }, 38 | "devDependencies": { 39 | "@nestjs/cli": "^8.0.0", 40 | "@nestjs/schematics": "^8.0.0", 41 | "@nestjs/testing": "^8.0.0", 42 | "@types/express": "^4.17.13", 43 | "@types/jest": "27.4.1", 44 | "@types/node": "^16.11.26", 45 | "@types/supertest": "^2.0.11", 46 | "@typescript-eslint/eslint-plugin": "^5.0.0", 47 | "@typescript-eslint/parser": "^5.0.0", 48 | "eslint": "^8.0.1", 49 | "eslint-config-prettier": "^8.3.0", 50 | "eslint-plugin-prettier": "^4.0.0", 51 | "jest": "^27.2.5", 52 | "prettier": "^2.3.2", 53 | "source-map-support": "^0.5.20", 54 | "supertest": "^6.1.3", 55 | "ts-jest": "^27.0.3", 56 | "ts-loader": "^9.2.3", 57 | "ts-node": "^10.0.0", 58 | "ts-proto": "^1.110.2", 59 | "tsconfig-paths": "^3.10.1", 60 | "typescript": "^4.3.5" 61 | }, 62 | "jest": { 63 | "moduleFileExtensions": [ 64 | "js", 65 | "json", 66 | "ts" 67 | ], 68 | "rootDir": "src", 69 | "testRegex": ".*\\.spec\\.ts$", 70 | "transform": { 71 | "^.+\\.(t|j)s$": "ts-jest" 72 | }, 73 | "collectCoverageFrom": [ 74 | "**/*.(t|j)s" 75 | ], 76 | "coverageDirectory": "../coverage", 77 | "testEnvironment": "node" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { BookModule } from './book/book.module'; 5 | import { GreetModule } from './greet/greet.module'; 6 | 7 | @Module({ 8 | imports: [BookModule, GreetModule], 9 | controllers: [AppController], 10 | providers: [AppService], 11 | }) 12 | export class AppModule {} 13 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/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 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/book/book.controller.ts: -------------------------------------------------------------------------------- 1 | 2 | import { BOOK_SERVICE_NAME,BOOK_PACKAGE_NAME, getBookByIdRequest, getBookByIdResponse, getBooksRequest, getBooksResponse, Book, BookServiceClient } from './book.pb'; 3 | import { Controller, Inject, Post, OnModuleInit, UseGuards, Req, Get, Param, ParseIntPipe } from '@nestjs/common'; 4 | import { ClientGrpc } from '@nestjs/microservices'; 5 | import { Observable } from 'rxjs'; 6 | import { Request } from 'express'; 7 | import { promises } from 'dns'; 8 | 9 | @Controller('book') 10 | export class BookController implements OnModuleInit{ 11 | private svc: BookServiceClient; 12 | 13 | @Inject(BOOK_SERVICE_NAME) 14 | private readonly client: ClientGrpc; 15 | 16 | public onModuleInit(): void { 17 | this.svc = this.client.getService(BOOK_SERVICE_NAME); 18 | } 19 | 20 | @Get() 21 | async getBooks() : Promise> { 22 | return await this.svc.getBooks(null) ; 23 | } 24 | 25 | @Get(':id') 26 | async getBookById(@Param('id') id:number): Promise> { 27 | console.log(id); 28 | return await this.svc.getBookById({id}); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/book/book.module.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Module } from '@nestjs/common'; 3 | import { BookController } from './book.controller'; 4 | import { ClientsModule, Transport } from '@nestjs/microservices'; 5 | import { BOOK_SERVICE_NAME, BOOK_PACKAGE_NAME } from './book.pb'; 6 | import {resolve} from 'path'; 7 | @Module({ 8 | controllers: [BookController], 9 | imports: [ 10 | ClientsModule.register([ 11 | { 12 | name: BOOK_SERVICE_NAME, 13 | transport: Transport.GRPC, 14 | options: { 15 | url: '0.0.0.0:50051', 16 | package: BOOK_PACKAGE_NAME, 17 | protoPath: resolve(__dirname, '../../../grpc-nest-proto/proto/book.proto') 18 | }, 19 | }, 20 | ]), 21 | ], 22 | }) 23 | export class BookModule {} 24 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/book/book.pb.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; 3 | import * as Long from "long"; 4 | import * as _m0 from "protobufjs/minimal"; 5 | import { Observable } from "rxjs"; 6 | 7 | export const protobufPackage = "book"; 8 | 9 | /** getBooks */ 10 | export interface getBooksRequest {} 11 | 12 | export interface getBooksResponse { 13 | books: Book[]; 14 | } 15 | 16 | export interface Book { 17 | id: number; 18 | title: string; 19 | description: string; 20 | author: string; 21 | } 22 | 23 | export interface getBookByIdRequest { 24 | id: number; 25 | } 26 | 27 | export interface getBookByIdResponse { 28 | book: Book | undefined; 29 | } 30 | 31 | export const BOOK_PACKAGE_NAME = "book"; 32 | 33 | export interface BookServiceClient { 34 | getBooks(request: getBooksRequest): Observable; 35 | 36 | getBookById(request: getBookByIdRequest): Observable; 37 | } 38 | 39 | export interface BookServiceController { 40 | getBooks( 41 | request: getBooksRequest 42 | ): 43 | | Promise 44 | | Observable 45 | | getBooksResponse; 46 | 47 | getBookById( 48 | request: getBookByIdRequest 49 | ): 50 | | Promise 51 | | Observable 52 | | getBookByIdResponse; 53 | } 54 | 55 | export function BookServiceControllerMethods() { 56 | return function (constructor: Function) { 57 | const grpcMethods: string[] = ["getBooks", "getBookById"]; 58 | for (const method of grpcMethods) { 59 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 60 | constructor.prototype, 61 | method 62 | ); 63 | GrpcMethod("BookService", method)( 64 | constructor.prototype[method], 65 | method, 66 | descriptor 67 | ); 68 | } 69 | const grpcStreamMethods: string[] = []; 70 | for (const method of grpcStreamMethods) { 71 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 72 | constructor.prototype, 73 | method 74 | ); 75 | GrpcStreamMethod("BookService", method)( 76 | constructor.prototype[method], 77 | method, 78 | descriptor 79 | ); 80 | } 81 | }; 82 | } 83 | 84 | export const BOOK_SERVICE_NAME = "BookService"; 85 | 86 | // If you get a compile-error about 'Constructor and ... have no overlap', 87 | // add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. 88 | if (_m0.util.Long !== Long) { 89 | _m0.util.Long = Long as any; 90 | _m0.configure(); 91 | } 92 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/greet/greet.controller.ts: -------------------------------------------------------------------------------- 1 | 2 | import { ClientGrpc } from '@nestjs/microservices'; 3 | import { Controller, Get, Inject, OnModuleInit, Param } from '@nestjs/common'; 4 | import { GreeterClient, HelloReply, GREETER_SERVICE_NAME } from './greet.pb'; 5 | import { Observable } from 'rxjs'; 6 | 7 | @Controller('greeter') 8 | export class GreetController implements OnModuleInit { 9 | private svc: GreeterClient; 10 | @Inject(GREETER_SERVICE_NAME) 11 | private readonly client: ClientGrpc; 12 | 13 | public onModuleInit(): void{ 14 | this.svc = this.client.getService(GREETER_SERVICE_NAME); 15 | } 16 | 17 | @Get(':name') 18 | async SayHello(@Param('name') name: string ): Promise>{ 19 | console.log(name); 20 | return await this.svc.sayHello({name}); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/greet/greet.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ClientsModule, Transport } from '@nestjs/microservices'; 3 | import { resolve } from 'path'; 4 | import { GreetController } from './greet.controller'; 5 | import { GREETER_SERVICE_NAME,GREET_PACKAGE_NAME } from './greet.pb'; 6 | @Module({ 7 | controllers: [GreetController], 8 | imports: [ 9 | ClientsModule.register([ 10 | { 11 | name: GREETER_SERVICE_NAME, 12 | transport: Transport.GRPC, 13 | options: { 14 | url: 'localhost:5284', 15 | package: GREET_PACKAGE_NAME, 16 | protoPath: resolve(__dirname, '../../../grpc-nest-proto/proto/greet.proto') 17 | }, 18 | }, 19 | ]), 20 | ], 21 | }) 22 | export class GreetModule {} 23 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/greet/greet.pb.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; 3 | import * as Long from "long"; 4 | import * as _m0 from "protobufjs/minimal"; 5 | import { Observable } from "rxjs"; 6 | 7 | export const protobufPackage = "greet"; 8 | 9 | /** The request message containing the user's name. */ 10 | export interface HelloRequest { 11 | name: string; 12 | } 13 | 14 | /** The response message containing the greetings. */ 15 | export interface HelloReply { 16 | message: string; 17 | } 18 | 19 | export const GREET_PACKAGE_NAME = "greet"; 20 | 21 | /** The greeting service definition. */ 22 | 23 | export interface GreeterClient { 24 | /** Sends a greeting */ 25 | 26 | sayHello(request: HelloRequest): Observable; 27 | } 28 | 29 | /** The greeting service definition. */ 30 | 31 | export interface GreeterController { 32 | /** Sends a greeting */ 33 | 34 | sayHello( 35 | request: HelloRequest 36 | ): Promise | Observable | HelloReply; 37 | } 38 | 39 | export function GreeterControllerMethods() { 40 | return function (constructor: Function) { 41 | const grpcMethods: string[] = ["sayHello"]; 42 | for (const method of grpcMethods) { 43 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 44 | constructor.prototype, 45 | method 46 | ); 47 | GrpcMethod("Greeter", method)( 48 | constructor.prototype[method], 49 | method, 50 | descriptor 51 | ); 52 | } 53 | const grpcStreamMethods: string[] = []; 54 | for (const method of grpcStreamMethods) { 55 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 56 | constructor.prototype, 57 | method 58 | ); 59 | GrpcStreamMethod("Greeter", method)( 60 | constructor.prototype[method], 61 | method, 62 | descriptor 63 | ); 64 | } 65 | }; 66 | } 67 | 68 | export const GREETER_SERVICE_NAME = "Greeter"; 69 | 70 | // If you get a compile-error about 'Constructor and ... have no overlap', 71 | // add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. 72 | if (_m0.util.Long !== Long) { 73 | _m0.util.Long = Long as any; 74 | _m0.configure(); 75 | } 76 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | import { MicroserviceOptions, Transport } from '@nestjs/microservices'; 4 | import * as path from 'path'; 5 | async function bootstrap() { 6 | const URL = 'localhost:50051'; 7 | const app = await NestFactory.create(AppModule); 8 | // const app = await NestFactory.createMicroservice( 9 | // AppModule, 10 | // { 11 | // transport: Transport.GRPC, 12 | // options: { 13 | // url: URL, 14 | // package: 'gateway', 15 | // protoPath: path.resolve(__dirname, './../grpc-nest-proto/proto/book.proto'), 16 | // }, 17 | // }, 18 | // ); 19 | 20 | await app.listen(3000); 21 | } 22 | bootstrap(); -------------------------------------------------------------------------------- /grpc-nest-api-gateway/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 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/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 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /grpc-nest-api-gateway/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 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/.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 | 'plugin:prettier/recommended', 11 | ], 12 | root: true, 13 | env: { 14 | node: true, 15 | jest: true, 16 | }, 17 | ignorePatterns: ['.eslintrc.js'], 18 | rules: { 19 | '@typescript-eslint/interface-name-prefix': 'off', 20 | '@typescript-eslint/explicit-function-return-type': 'off', 21 | '@typescript-eslint/explicit-module-boundary-types': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json -------------------------------------------------------------------------------- /grpc-nest-book-svc/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /grpc-nest-book-svc/README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 6 | [circleci-url]: https://circleci.com/gh/nestjs/nest 7 | 8 |

A progressive Node.js framework for building efficient and scalable server-side applications.

9 |

10 | NPM Version 11 | Package License 12 | NPM Downloads 13 | CircleCI 14 | Coverage 15 | Discord 16 | Backers on Open Collective 17 | Sponsors on Open Collective 18 | 19 | Support us 20 | 21 |

22 | 24 | 25 | ## Description 26 | 27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 28 | 29 | ## Installation 30 | 31 | ```bash 32 | $ npm install 33 | ``` 34 | 35 | ## Running the app 36 | 37 | ```bash 38 | # development 39 | $ npm run start 40 | 41 | # watch mode 42 | $ npm run start:dev 43 | 44 | # production mode 45 | $ npm run start:prod 46 | ``` 47 | 48 | ## Test 49 | 50 | ```bash 51 | # unit tests 52 | $ npm run test 53 | 54 | # e2e tests 55 | $ npm run test:e2e 56 | 57 | # test coverage 58 | $ npm run test:cov 59 | ``` 60 | 61 | ## Support 62 | 63 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 64 | 65 | ## Stay in touch 66 | 67 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 68 | - Website - [https://nestjs.com](https://nestjs.com/) 69 | - Twitter - [@nestframework](https://twitter.com/nestframework) 70 | 71 | ## License 72 | 73 | Nest is [MIT licensed](LICENSE). 74 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/images/bookservicetesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itsmebhavin/nestjs-microservices-gRPC-example/ab05cfb4605a49c27ed158e0241e98dfe07502db/grpc-nest-book-svc/images/bookservicetesting.png -------------------------------------------------------------------------------- /grpc-nest-book-svc/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grpc-nest-book-svc", 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": "node dist/grpc-nest-book-svc/src/main --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 | }, 23 | "dependencies": { 24 | "@grpc/grpc-js": "^1.6.2", 25 | "@grpc/proto-loader": "^0.6.9", 26 | "@nestjs/common": "^8.0.0", 27 | "@nestjs/core": "^8.0.0", 28 | "@nestjs/microservices": "^8.4.4", 29 | "@nestjs/platform-express": "^8.0.0", 30 | "@nestjs/typeorm": "^8.0.3", 31 | "class-transformer": "^0.5.1", 32 | "class-validator": "^0.13.2", 33 | "pg": "^8.7.3", 34 | "reflect-metadata": "^0.1.13", 35 | "rimraf": "^3.0.2", 36 | "rxjs": "^7.2.0", 37 | "typeorm": "^0.3.5" 38 | }, 39 | "devDependencies": { 40 | "@nestjs/cli": "^8.0.0", 41 | "@nestjs/schematics": "^8.0.0", 42 | "@nestjs/testing": "^8.0.0", 43 | "@types/express": "^4.17.13", 44 | "@types/jest": "27.4.1", 45 | "@types/node": "^16.11.26", 46 | "@types/supertest": "^2.0.11", 47 | "@typescript-eslint/eslint-plugin": "^5.0.0", 48 | "@typescript-eslint/parser": "^5.0.0", 49 | "eslint": "^8.0.1", 50 | "eslint-config-prettier": "^8.3.0", 51 | "eslint-plugin-prettier": "^4.0.0", 52 | "jest": "^27.2.5", 53 | "prettier": "^2.3.2", 54 | "source-map-support": "^0.5.20", 55 | "supertest": "^6.1.3", 56 | "ts-jest": "^27.0.3", 57 | "ts-loader": "^9.2.3", 58 | "ts-node": "^10.0.0", 59 | "ts-proto": "^1.110.2", 60 | "tsconfig-paths": "^3.10.1", 61 | "typescript": "^4.3.5" 62 | }, 63 | "jest": { 64 | "moduleFileExtensions": [ 65 | "js", 66 | "json", 67 | "ts" 68 | ], 69 | "rootDir": "src", 70 | "testRegex": ".*\\.spec\\.ts$", 71 | "transform": { 72 | "^.+\\.(t|j)s$": "ts-jest" 73 | }, 74 | "collectCoverageFrom": [ 75 | "**/*.(t|j)s" 76 | ], 77 | "coverageDirectory": "../coverage", 78 | "testEnvironment": "node" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/src/book.controller.ts: -------------------------------------------------------------------------------- 1 | import { getBooksRequest, getBooksResponse,Book, getBookByIdResponse } from '../../grpc-nest-proto/build/proto/book.pb'; 2 | import { Controller, Get } from '@nestjs/common'; 3 | import { BookService } from './book.service'; 4 | import { GrpcMethod } from '@nestjs/microservices'; 5 | 6 | 7 | 8 | @Controller('book') 9 | export class BookController { 10 | constructor(private readonly bookService: BookService) {} 11 | 12 | @GrpcMethod('BookService','getBooks') 13 | @Get() 14 | async getBooks(getBooksRequest): Promise { 15 | return { books: await this.bookService.getBooks() } 16 | } 17 | 18 | @GrpcMethod('BookService','getBookById') 19 | @Get(':id') 20 | async getBookById(id:number): Promise { 21 | return {book: await this.bookService.getBookById(id)} 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/src/book.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { BookController } from './book.controller'; 3 | import { BookService } from './book.service'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [BookController], 8 | providers: [BookService], 9 | }) 10 | export class BookModule {} 11 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/src/book.service.ts: -------------------------------------------------------------------------------- 1 | import { getBooksResponse,Book } from '../../grpc-nest-proto/build/proto/book.pb'; 2 | import { Injectable, HttpException } from '@nestjs/common'; 3 | import { GrpcMethod } from '@nestjs/microservices'; 4 | import { BOOKS } from './books.mock'; 5 | 6 | @Injectable() 7 | export class BookService { 8 | books = BOOKS; 9 | 10 | getBooks(): Promise { 11 | return new Promise(resolve => { 12 | resolve(this.books); 13 | }); 14 | } 15 | 16 | getBookById(param): Promise { 17 | 18 | console.log(param); 19 | return new Promise(resolve => { 20 | const book = this.books.find($book => $book.id === param.id); 21 | if (!book) { 22 | throw new HttpException('Book does not exist!', 404); 23 | } 24 | resolve(book); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/src/books.mock.ts: -------------------------------------------------------------------------------- 1 | // ./src/mocks/books.mock.ts 2 | export const BOOKS = [ 3 | { 4 | id: 1, 5 | title: 'First book', 6 | description: 'This is the description for the first book', 7 | author: 'Olususi Oluyemi', 8 | }, 9 | { 10 | id: 2, 11 | title: 'Second book', 12 | description: 'This is the description for the second book', 13 | author: 'John Barry', 14 | }, 15 | { 16 | id: 3, 17 | title: 'Third book', 18 | description: 'This is the description for the third book', 19 | author: 'Clement Wilfred', 20 | }, 21 | { 22 | id: 4, 23 | title: 'Fourth book', 24 | description: 'This is the description for the fourth book', 25 | author: 'Christian nwamba', 26 | }, 27 | { 28 | id: 5, 29 | title: 'Fifth book', 30 | description: 'This is the description for the fifth book', 31 | author: 'Chris anderson', 32 | }, 33 | { 34 | id: 6, 35 | title: 'Sixth book', 36 | description: 'This is the description for the sixth book', 37 | author: 'Olususi Oluyemi', 38 | }, 39 | ]; -------------------------------------------------------------------------------- /grpc-nest-book-svc/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import {Transport} from '@nestjs/microservices'; 3 | import { BookModule } from './book.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.createMicroservice(BookModule, { 7 | transport: Transport.GRPC, 8 | options: { 9 | url: '0.0.0.0:50051', 10 | protoPath: './../grpc-nest-proto/proto/book.proto', 11 | package: 'book', 12 | }, 13 | }); 14 | 15 | // tslint:disable-next-line: no-console 16 | app.listen(); 17 | } 18 | bootstrap(); -------------------------------------------------------------------------------- /grpc-nest-book-svc/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 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/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 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /grpc-nest-book-svc/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 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /grpc-nest-proto/build/proto/book.pb.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; 3 | import * as Long from "long"; 4 | import * as _m0 from "protobufjs/minimal"; 5 | import { Observable } from "rxjs"; 6 | 7 | export const protobufPackage = "book"; 8 | 9 | /** getBooks */ 10 | export interface getBooksRequest {} 11 | 12 | export interface getBooksResponse { 13 | books: Book[]; 14 | } 15 | 16 | export interface Book { 17 | id: number; 18 | title: string; 19 | description: string; 20 | author: string; 21 | } 22 | 23 | export interface getBookByIdRequest { 24 | id: number; 25 | } 26 | 27 | export interface getBookByIdResponse { 28 | book: Book | undefined; 29 | } 30 | 31 | export const BOOK_PACKAGE_NAME = "book"; 32 | 33 | export interface BookServiceClient { 34 | getBooks(request: getBooksRequest): Observable; 35 | 36 | getBookById(request: getBookByIdRequest): Observable; 37 | } 38 | 39 | export interface BookServiceController { 40 | getBooks( 41 | request: getBooksRequest 42 | ): 43 | | Promise 44 | | Observable 45 | | getBooksResponse; 46 | 47 | getBookById( 48 | request: getBookByIdRequest 49 | ): 50 | | Promise 51 | | Observable 52 | | getBookByIdResponse; 53 | } 54 | 55 | export function BookServiceControllerMethods() { 56 | return function (constructor: Function) { 57 | const grpcMethods: string[] = ["getBooks", "getBookById"]; 58 | for (const method of grpcMethods) { 59 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 60 | constructor.prototype, 61 | method 62 | ); 63 | GrpcMethod("BookService", method)( 64 | constructor.prototype[method], 65 | method, 66 | descriptor 67 | ); 68 | } 69 | const grpcStreamMethods: string[] = []; 70 | for (const method of grpcStreamMethods) { 71 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 72 | constructor.prototype, 73 | method 74 | ); 75 | GrpcStreamMethod("BookService", method)( 76 | constructor.prototype[method], 77 | method, 78 | descriptor 79 | ); 80 | } 81 | }; 82 | } 83 | 84 | export const BOOK_SERVICE_NAME = "BookService"; 85 | 86 | // If you get a compile-error about 'Constructor and ... have no overlap', 87 | // add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. 88 | if (_m0.util.Long !== Long) { 89 | _m0.util.Long = Long as any; 90 | _m0.configure(); 91 | } 92 | -------------------------------------------------------------------------------- /grpc-nest-proto/build/proto/greet.pb.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; 3 | import * as Long from "long"; 4 | import * as _m0 from "protobufjs/minimal"; 5 | import { Observable } from "rxjs"; 6 | 7 | export const protobufPackage = "greet"; 8 | 9 | /** The request message containing the user's name. */ 10 | export interface HelloRequest { 11 | name: string; 12 | } 13 | 14 | /** The response message containing the greetings. */ 15 | export interface HelloReply { 16 | message: string; 17 | } 18 | 19 | export const GREET_PACKAGE_NAME = "greet"; 20 | 21 | /** The greeting service definition. */ 22 | 23 | export interface GreeterClient { 24 | /** Sends a greeting */ 25 | 26 | sayHello(request: HelloRequest): Observable; 27 | } 28 | 29 | /** The greeting service definition. */ 30 | 31 | export interface GreeterController { 32 | /** Sends a greeting */ 33 | 34 | sayHello( 35 | request: HelloRequest 36 | ): Promise | Observable | HelloReply; 37 | } 38 | 39 | export function GreeterControllerMethods() { 40 | return function (constructor: Function) { 41 | const grpcMethods: string[] = ["sayHello"]; 42 | for (const method of grpcMethods) { 43 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 44 | constructor.prototype, 45 | method 46 | ); 47 | GrpcMethod("Greeter", method)( 48 | constructor.prototype[method], 49 | method, 50 | descriptor 51 | ); 52 | } 53 | const grpcStreamMethods: string[] = []; 54 | for (const method of grpcStreamMethods) { 55 | const descriptor: any = Reflect.getOwnPropertyDescriptor( 56 | constructor.prototype, 57 | method 58 | ); 59 | GrpcStreamMethod("Greeter", method)( 60 | constructor.prototype[method], 61 | method, 62 | descriptor 63 | ); 64 | } 65 | }; 66 | } 67 | 68 | export const GREETER_SERVICE_NAME = "Greeter"; 69 | 70 | // If you get a compile-error about 'Constructor and ... have no overlap', 71 | // add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. 72 | if (_m0.util.Long !== Long) { 73 | _m0.util.Long = Long as any; 74 | _m0.configure(); 75 | } 76 | -------------------------------------------------------------------------------- /grpc-nest-proto/compile.proto.sh: -------------------------------------------------------------------------------- 1 | protoc \ 2 | --plugin=./node_modules/.bin/protoc-gen-ts_proto.cmd \ 3 | --ts_proto_out=./build ./proto/*.proto \ 4 | --ts_proto_opt=nestJs=true \ 5 | --ts_proto_opt=fileSuffix=.pb -------------------------------------------------------------------------------- /grpc-nest-proto/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grpc-nest-proto", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "grpc-nest-proto", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@nestjs/microservices": "^8.4.3", 13 | "rxjs": "^7.5.5", 14 | "ts-proto": "^1.110.2" 15 | } 16 | }, 17 | "node_modules/@nestjs/microservices": { 18 | "version": "8.4.3", 19 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@nestjs/microservices/-/microservices-8.4.3.tgz", 20 | "integrity": "sha1-l9r5RfzNQPsVvDrf/ec6xs7Zcfo=", 21 | "license": "MIT", 22 | "dependencies": { 23 | "iterare": "1.2.1", 24 | "json-socket": "0.3.0", 25 | "tslib": "2.3.1" 26 | }, 27 | "funding": { 28 | "type": "opencollective", 29 | "url": "https://opencollective.com/nest" 30 | }, 31 | "peerDependencies": { 32 | "@grpc/grpc-js": "*", 33 | "@nestjs/common": "^8.0.0", 34 | "@nestjs/core": "^8.0.0", 35 | "@nestjs/websockets": "^8.0.0", 36 | "amqp-connection-manager": "*", 37 | "amqplib": "*", 38 | "cache-manager": "*", 39 | "kafkajs": "*", 40 | "mqtt": "*", 41 | "nats": "*", 42 | "redis": "*", 43 | "reflect-metadata": "^0.1.12", 44 | "rxjs": "^7.1.0" 45 | }, 46 | "peerDependenciesMeta": { 47 | "@grpc/grpc-js": { 48 | "optional": true 49 | }, 50 | "@nestjs/websockets": { 51 | "optional": true 52 | }, 53 | "amqp-connection-manager": { 54 | "optional": true 55 | }, 56 | "amqplib": { 57 | "optional": true 58 | }, 59 | "cache-manager": { 60 | "optional": true 61 | }, 62 | "kafkajs": { 63 | "optional": true 64 | }, 65 | "mqtt": { 66 | "optional": true 67 | }, 68 | "nats": { 69 | "optional": true 70 | }, 71 | "redis": { 72 | "optional": true 73 | } 74 | } 75 | }, 76 | "node_modules/@protobufjs/aspromise": { 77 | "version": "1.1.2", 78 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", 79 | "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", 80 | "license": "BSD-3-Clause" 81 | }, 82 | "node_modules/@protobufjs/base64": { 83 | "version": "1.1.2", 84 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/base64/-/base64-1.1.2.tgz", 85 | "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=", 86 | "license": "BSD-3-Clause" 87 | }, 88 | "node_modules/@protobufjs/codegen": { 89 | "version": "2.0.4", 90 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/codegen/-/codegen-2.0.4.tgz", 91 | "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=", 92 | "license": "BSD-3-Clause" 93 | }, 94 | "node_modules/@protobufjs/eventemitter": { 95 | "version": "1.1.0", 96 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", 97 | "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", 98 | "license": "BSD-3-Clause" 99 | }, 100 | "node_modules/@protobufjs/fetch": { 101 | "version": "1.1.0", 102 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/fetch/-/fetch-1.1.0.tgz", 103 | "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", 104 | "license": "BSD-3-Clause", 105 | "dependencies": { 106 | "@protobufjs/aspromise": "^1.1.1", 107 | "@protobufjs/inquire": "^1.1.0" 108 | } 109 | }, 110 | "node_modules/@protobufjs/float": { 111 | "version": "1.0.2", 112 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/float/-/float-1.0.2.tgz", 113 | "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", 114 | "license": "BSD-3-Clause" 115 | }, 116 | "node_modules/@protobufjs/inquire": { 117 | "version": "1.1.0", 118 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/inquire/-/inquire-1.1.0.tgz", 119 | "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", 120 | "license": "BSD-3-Clause" 121 | }, 122 | "node_modules/@protobufjs/path": { 123 | "version": "1.1.2", 124 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/path/-/path-1.1.2.tgz", 125 | "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", 126 | "license": "BSD-3-Clause" 127 | }, 128 | "node_modules/@protobufjs/pool": { 129 | "version": "1.1.0", 130 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/pool/-/pool-1.1.0.tgz", 131 | "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", 132 | "license": "BSD-3-Clause" 133 | }, 134 | "node_modules/@protobufjs/utf8": { 135 | "version": "1.1.0", 136 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/utf8/-/utf8-1.1.0.tgz", 137 | "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", 138 | "license": "BSD-3-Clause" 139 | }, 140 | "node_modules/@types/long": { 141 | "version": "4.0.1", 142 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/long/-/long-4.0.1.tgz", 143 | "integrity": "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek=", 144 | "license": "MIT" 145 | }, 146 | "node_modules/@types/node": { 147 | "version": "17.0.23", 148 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/node/-/node-17.0.23.tgz", 149 | "integrity": "sha1-O0Gm5kNYmsZEK9vXpKPe1i8z99o=", 150 | "license": "MIT" 151 | }, 152 | "node_modules/@types/object-hash": { 153 | "version": "1.3.4", 154 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/object-hash/-/object-hash-1.3.4.tgz", 155 | "integrity": "sha1-B5uhQr5lgzKTZzJUgxtePoR/5Ys=", 156 | "license": "MIT" 157 | }, 158 | "node_modules/dataloader": { 159 | "version": "1.4.0", 160 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/dataloader/-/dataloader-1.4.0.tgz", 161 | "integrity": "sha1-vKEdhn9dPxue2fc3vRWXDGXf9cg=", 162 | "license": "BSD-3-Clause" 163 | }, 164 | "node_modules/iterare": { 165 | "version": "1.2.1", 166 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/iterare/-/iterare-1.2.1.tgz", 167 | "integrity": "sha1-E5xAD/c2NpDjOr/6M8u6iSDwAEI=", 168 | "license": "ISC", 169 | "engines": { 170 | "node": ">=6" 171 | } 172 | }, 173 | "node_modules/json-socket": { 174 | "version": "0.3.0", 175 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/json-socket/-/json-socket-0.3.0.tgz", 176 | "integrity": "sha1-9LlTxoW7jovQtyQ49SCNmgeZrgc=" 177 | }, 178 | "node_modules/lodash": { 179 | "version": "4.17.21", 180 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/lodash/-/lodash-4.17.21.tgz", 181 | "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=", 182 | "license": "MIT" 183 | }, 184 | "node_modules/long": { 185 | "version": "4.0.0", 186 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/long/-/long-4.0.0.tgz", 187 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 188 | "license": "Apache-2.0" 189 | }, 190 | "node_modules/object-hash": { 191 | "version": "1.3.1", 192 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/object-hash/-/object-hash-1.3.1.tgz", 193 | "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=", 194 | "license": "MIT", 195 | "engines": { 196 | "node": ">= 0.10.0" 197 | } 198 | }, 199 | "node_modules/prettier": { 200 | "version": "2.6.2", 201 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/prettier/-/prettier-2.6.2.tgz", 202 | "integrity": "sha1-4m1xoYp0w9DwWX9V8B+2wGwgYDI=", 203 | "license": "MIT", 204 | "bin": { 205 | "prettier": "bin-prettier.js" 206 | }, 207 | "engines": { 208 | "node": ">=10.13.0" 209 | }, 210 | "funding": { 211 | "url": "https://github.com/prettier/prettier?sponsor=1" 212 | } 213 | }, 214 | "node_modules/protobufjs": { 215 | "version": "6.11.2", 216 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/protobufjs/-/protobufjs-6.11.2.tgz", 217 | "integrity": "sha1-3jn6vU7TK+qgjpux4w0IVEwe34s=", 218 | "hasInstallScript": true, 219 | "license": "BSD-3-Clause", 220 | "dependencies": { 221 | "@protobufjs/aspromise": "^1.1.2", 222 | "@protobufjs/base64": "^1.1.2", 223 | "@protobufjs/codegen": "^2.0.4", 224 | "@protobufjs/eventemitter": "^1.1.0", 225 | "@protobufjs/fetch": "^1.1.0", 226 | "@protobufjs/float": "^1.0.2", 227 | "@protobufjs/inquire": "^1.1.0", 228 | "@protobufjs/path": "^1.1.2", 229 | "@protobufjs/pool": "^1.1.0", 230 | "@protobufjs/utf8": "^1.1.0", 231 | "@types/long": "^4.0.1", 232 | "@types/node": ">=13.7.0", 233 | "long": "^4.0.0" 234 | }, 235 | "bin": { 236 | "pbjs": "bin/pbjs", 237 | "pbts": "bin/pbts" 238 | } 239 | }, 240 | "node_modules/rxjs": { 241 | "version": "7.5.5", 242 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/rxjs/-/rxjs-7.5.5.tgz", 243 | "integrity": "sha1-LrrYmvD1YPRgrVzEITIZ4ffdTp8=", 244 | "license": "Apache-2.0", 245 | "dependencies": { 246 | "tslib": "^2.1.0" 247 | } 248 | }, 249 | "node_modules/ts-poet": { 250 | "version": "4.11.0", 251 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-poet/-/ts-poet-4.11.0.tgz", 252 | "integrity": "sha1-VWb0mex2eSDMGLl3Yk8ITFLoc0o=", 253 | "license": "Apache-2.0", 254 | "dependencies": { 255 | "lodash": "^4.17.15", 256 | "prettier": "^2.5.1" 257 | } 258 | }, 259 | "node_modules/ts-proto": { 260 | "version": "1.110.2", 261 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-proto/-/ts-proto-1.110.2.tgz", 262 | "integrity": "sha1-hXs2snpyrikgEl+ihMrdkca7ETc=", 263 | "license": "ISC", 264 | "dependencies": { 265 | "@types/object-hash": "^1.3.0", 266 | "dataloader": "^1.4.0", 267 | "object-hash": "^1.3.1", 268 | "protobufjs": "^6.8.8", 269 | "ts-poet": "^4.11.0", 270 | "ts-proto-descriptors": "1.6.0" 271 | }, 272 | "bin": { 273 | "protoc-gen-ts_proto": "protoc-gen-ts_proto" 274 | } 275 | }, 276 | "node_modules/ts-proto-descriptors": { 277 | "version": "1.6.0", 278 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-proto-descriptors/-/ts-proto-descriptors-1.6.0.tgz", 279 | "integrity": "sha1-ym6vyIJJWi6SDaW5gdexgbTknDg=", 280 | "license": "ISC", 281 | "dependencies": { 282 | "long": "^4.0.0", 283 | "protobufjs": "^6.8.8" 284 | } 285 | }, 286 | "node_modules/tslib": { 287 | "version": "2.3.1", 288 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/tslib/-/tslib-2.3.1.tgz", 289 | "integrity": "sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE=", 290 | "license": "0BSD" 291 | } 292 | }, 293 | "dependencies": { 294 | "@nestjs/microservices": { 295 | "version": "8.4.3", 296 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@nestjs/microservices/-/microservices-8.4.3.tgz", 297 | "integrity": "sha1-l9r5RfzNQPsVvDrf/ec6xs7Zcfo=", 298 | "requires": { 299 | "iterare": "1.2.1", 300 | "json-socket": "0.3.0", 301 | "tslib": "2.3.1" 302 | } 303 | }, 304 | "@protobufjs/aspromise": { 305 | "version": "1.1.2", 306 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", 307 | "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" 308 | }, 309 | "@protobufjs/base64": { 310 | "version": "1.1.2", 311 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/base64/-/base64-1.1.2.tgz", 312 | "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" 313 | }, 314 | "@protobufjs/codegen": { 315 | "version": "2.0.4", 316 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/codegen/-/codegen-2.0.4.tgz", 317 | "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" 318 | }, 319 | "@protobufjs/eventemitter": { 320 | "version": "1.1.0", 321 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", 322 | "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" 323 | }, 324 | "@protobufjs/fetch": { 325 | "version": "1.1.0", 326 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/fetch/-/fetch-1.1.0.tgz", 327 | "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", 328 | "requires": { 329 | "@protobufjs/aspromise": "^1.1.1", 330 | "@protobufjs/inquire": "^1.1.0" 331 | } 332 | }, 333 | "@protobufjs/float": { 334 | "version": "1.0.2", 335 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/float/-/float-1.0.2.tgz", 336 | "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" 337 | }, 338 | "@protobufjs/inquire": { 339 | "version": "1.1.0", 340 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/inquire/-/inquire-1.1.0.tgz", 341 | "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" 342 | }, 343 | "@protobufjs/path": { 344 | "version": "1.1.2", 345 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/path/-/path-1.1.2.tgz", 346 | "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" 347 | }, 348 | "@protobufjs/pool": { 349 | "version": "1.1.0", 350 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/pool/-/pool-1.1.0.tgz", 351 | "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" 352 | }, 353 | "@protobufjs/utf8": { 354 | "version": "1.1.0", 355 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@protobufjs/utf8/-/utf8-1.1.0.tgz", 356 | "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" 357 | }, 358 | "@types/long": { 359 | "version": "4.0.1", 360 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/long/-/long-4.0.1.tgz", 361 | "integrity": "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek=" 362 | }, 363 | "@types/node": { 364 | "version": "17.0.23", 365 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/node/-/node-17.0.23.tgz", 366 | "integrity": "sha1-O0Gm5kNYmsZEK9vXpKPe1i8z99o=" 367 | }, 368 | "@types/object-hash": { 369 | "version": "1.3.4", 370 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/@types/object-hash/-/object-hash-1.3.4.tgz", 371 | "integrity": "sha1-B5uhQr5lgzKTZzJUgxtePoR/5Ys=" 372 | }, 373 | "dataloader": { 374 | "version": "1.4.0", 375 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/dataloader/-/dataloader-1.4.0.tgz", 376 | "integrity": "sha1-vKEdhn9dPxue2fc3vRWXDGXf9cg=" 377 | }, 378 | "iterare": { 379 | "version": "1.2.1", 380 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/iterare/-/iterare-1.2.1.tgz", 381 | "integrity": "sha1-E5xAD/c2NpDjOr/6M8u6iSDwAEI=" 382 | }, 383 | "json-socket": { 384 | "version": "0.3.0", 385 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/json-socket/-/json-socket-0.3.0.tgz", 386 | "integrity": "sha1-9LlTxoW7jovQtyQ49SCNmgeZrgc=" 387 | }, 388 | "lodash": { 389 | "version": "4.17.21", 390 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/lodash/-/lodash-4.17.21.tgz", 391 | "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=" 392 | }, 393 | "long": { 394 | "version": "4.0.0", 395 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/long/-/long-4.0.0.tgz", 396 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" 397 | }, 398 | "object-hash": { 399 | "version": "1.3.1", 400 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/object-hash/-/object-hash-1.3.1.tgz", 401 | "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=" 402 | }, 403 | "prettier": { 404 | "version": "2.6.2", 405 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/prettier/-/prettier-2.6.2.tgz", 406 | "integrity": "sha1-4m1xoYp0w9DwWX9V8B+2wGwgYDI=" 407 | }, 408 | "protobufjs": { 409 | "version": "6.11.2", 410 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/protobufjs/-/protobufjs-6.11.2.tgz", 411 | "integrity": "sha1-3jn6vU7TK+qgjpux4w0IVEwe34s=", 412 | "requires": { 413 | "@protobufjs/aspromise": "^1.1.2", 414 | "@protobufjs/base64": "^1.1.2", 415 | "@protobufjs/codegen": "^2.0.4", 416 | "@protobufjs/eventemitter": "^1.1.0", 417 | "@protobufjs/fetch": "^1.1.0", 418 | "@protobufjs/float": "^1.0.2", 419 | "@protobufjs/inquire": "^1.1.0", 420 | "@protobufjs/path": "^1.1.2", 421 | "@protobufjs/pool": "^1.1.0", 422 | "@protobufjs/utf8": "^1.1.0", 423 | "@types/long": "^4.0.1", 424 | "@types/node": ">=13.7.0", 425 | "long": "^4.0.0" 426 | } 427 | }, 428 | "rxjs": { 429 | "version": "7.5.5", 430 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/rxjs/-/rxjs-7.5.5.tgz", 431 | "integrity": "sha1-LrrYmvD1YPRgrVzEITIZ4ffdTp8=", 432 | "requires": { 433 | "tslib": "^2.1.0" 434 | } 435 | }, 436 | "ts-poet": { 437 | "version": "4.11.0", 438 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-poet/-/ts-poet-4.11.0.tgz", 439 | "integrity": "sha1-VWb0mex2eSDMGLl3Yk8ITFLoc0o=", 440 | "requires": { 441 | "lodash": "^4.17.15", 442 | "prettier": "^2.5.1" 443 | } 444 | }, 445 | "ts-proto": { 446 | "version": "1.110.2", 447 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-proto/-/ts-proto-1.110.2.tgz", 448 | "integrity": "sha1-hXs2snpyrikgEl+ihMrdkca7ETc=", 449 | "requires": { 450 | "@types/object-hash": "^1.3.0", 451 | "dataloader": "^1.4.0", 452 | "object-hash": "^1.3.1", 453 | "protobufjs": "^6.8.8", 454 | "ts-poet": "^4.11.0", 455 | "ts-proto-descriptors": "1.6.0" 456 | } 457 | }, 458 | "ts-proto-descriptors": { 459 | "version": "1.6.0", 460 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/ts-proto-descriptors/-/ts-proto-descriptors-1.6.0.tgz", 461 | "integrity": "sha1-ym6vyIJJWi6SDaW5gdexgbTknDg=", 462 | "requires": { 463 | "long": "^4.0.0", 464 | "protobufjs": "^6.8.8" 465 | } 466 | }, 467 | "tslib": { 468 | "version": "2.3.1", 469 | "resolved": "https://pkgs.dev.azure.com/uacaps/_packaging/caps-global/npm/registry/tslib/-/tslib-2.3.1.tgz", 470 | "integrity": "sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE=" 471 | } 472 | } 473 | } 474 | -------------------------------------------------------------------------------- /grpc-nest-proto/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grpc-nest-proto", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "proto:book": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/book/ ../grpc-nest-proto/proto/book.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 9 | "proto:magazine": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/magazine/ ../grpc-nest-proto/proto/magazine.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 10 | "proto:all": "npm run proto:book && npm run proto:magazine" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@nestjs/microservices": "^8.4.3", 17 | "rxjs": "^7.5.5", 18 | "ts-proto": "^1.110.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /grpc-nest-proto/proto/book.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package book; 4 | 5 | service BookService { 6 | rpc getBooks (getBooksRequest) returns (getBooksResponse) {} 7 | rpc getBookById (getBookByIdRequest) returns (getBookByIdResponse) {} 8 | } 9 | 10 | // getBooks 11 | message getBooksRequest{ 12 | 13 | } 14 | message getBooksResponse { 15 | repeated Book books = 1; 16 | } 17 | 18 | message Book { 19 | int32 id =1; 20 | string title = 2; 21 | string description = 3; 22 | string author = 4; 23 | } 24 | 25 | // getBookById 26 | 27 | message getBookByIdRequest { 28 | int32 id = 1; 29 | } 30 | 31 | message getBookByIdResponse { 32 | Book book =1; 33 | } -------------------------------------------------------------------------------- /grpc-nest-proto/proto/greet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option csharp_namespace = "aspnetcore_api"; 4 | 5 | package greet; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply); 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings. 19 | message HelloReply { 20 | string message = 1; 21 | } 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 | 9 | 10 | 11 | 12 | 13 | 20 | 21 | 22 |
23 |
24 | 25 |

gRPC Microservices

26 |
nestjs-microservices-gRPC-example
27 | 28 |

29 | gRPC Microservices example using nest.js and asp.net core microservices and nest.js based gateway API to consume in client app. 30 |
31 | Explore the docs » 32 |
33 |
34 | Report Bug 35 | · 36 | Request Feature 37 |

38 |
39 | 40 | ![System Design](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/gRPC%20microservice%20example%20diagram.png) 41 | 42 | 43 | 71 | 72 | 73 | 74 | ## About The Project 75 | 76 | Micorservices example using gRPC. Two microservices written in nest.js and ASP.NET Core using gRPC. Both of them connect to the gateway API (written in nest.js) using common **proto** file interfaces. No need to install Redis or RabbitMQ etc. as communication happen on RPC. 77 | 78 | ### Why gRPC? 79 | 80 | gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services. 81 | 82 | #### Communication Patterns in gRPC 83 | In gRPC, a communication pattern describes how messages are encoded and interpreted between the client and server. There are several communication patterns in gRPC, such as the following: 84 | 85 | - Unary RPC: A client submits only one request and receives only one response in unary RPC. 86 | - Server streaming: A client transmits a request to the server and receives streams of messages in response. The server provides a status message once all data is transmitted. 87 | - Client-streaming: Unlike server-streaming, client-streaming involves a client sending a stream of messages to a server. After the messages are sent, the client awaits the server's response. 88 | - Bidirectional-streaming: Bidirectional streaming allows clients and servers to exchange messages in any order. 89 | 90 | ### Why nest.js? 91 | NestJS is a framework for building efficient, scalable Node.js web applications. It uses modern JavaScript and is built with TypeScript. If you develop an API built with TypeScript, then NestJS is the way to go! It’s heavily inspired by Spring and Angular. 92 | 93 | ### What is an API Gateway? 94 | An API gateway is an entry point for all clients, in our case, for all client requests based on HTTP, but it doesn’t need to be limited to HTTP only. The API gateway handles requests in one of two ways. Some requests are simply proxied/routed to the appropriate service. It handles other requests by fanning out to multiple services 95 | 96 |

(back to top)

97 | 98 | 99 | ### Built With 100 | 101 | * [Nest.js](https://docs.nestjs.com/microservices/grpc) 102 | * [gRPC](https://grpc.io/) 103 | * [ProtoBuf](https://github.com/protocolbuffers/protobuf) 104 | * [gRPC on .NET](https://docs.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-6.0) 105 | * [Visual Studio Code](https://code.visualstudio.com/) 106 | 107 | 108 |

(back to top)

109 | 110 | 111 | 112 | 113 | ## Getting Started 114 | 115 | Here is the outline we are going to do - 116 | 1. Common proto folder with **proto** files 117 | 2. nest.js microservice 118 | 3. .NET core microservice 119 | 4. nest.js gateway 120 | 121 | ### Proto folder 122 | 123 | ***grpc-nest-proto*** 124 | ``` 125 | $ cd grpc-nest-proto 126 | $ npm init --y 127 | $ git init 128 | $ mkdir proto 129 | $ touch proto/book.proto && touch proto/greet.proto 130 | $ code . 131 | ``` 132 | Now we have the proto folder and two files book.proto and greet.proto available. We are going to use book.proto in nest.js microservice and greet.proto in .NET Core microservice. 133 | 134 | ``` 135 | //book.proto 136 | syntax = "proto3"; 137 | 138 | package book; 139 | 140 | service BookService { 141 | rpc getBooks (getBooksRequest) returns (getBooksResponse) {} 142 | rpc getBookById (getBookByIdRequest) returns (getBookByIdResponse) {} 143 | } 144 | 145 | // getBooks 146 | message getBooksRequest{ 147 | 148 | } 149 | message getBooksResponse { 150 | repeated Book books = 1; 151 | } 152 | 153 | message Book { 154 | int32 id =1; 155 | string title = 2; 156 | string description = 3; 157 | string author = 4; 158 | } 159 | 160 | // getBookById 161 | 162 | message getBookByIdRequest { 163 | int32 id = 1; 164 | } 165 | 166 | message getBookByIdResponse { 167 | Book book =1; 168 | } 169 | ``` 170 | Book.proto has two methods to implement. getBooks and getBookById. 171 | 172 | ``` 173 | // Greet.proto 174 | syntax = "proto3"; 175 | 176 | option csharp_namespace = "aspnetcore_api"; 177 | 178 | package greet; 179 | 180 | // The greeting service definition. 181 | service Greeter { 182 | // Sends a greeting 183 | rpc SayHello (HelloRequest) returns (HelloReply); 184 | } 185 | 186 | // The request message containing the user's name. 187 | message HelloRequest { 188 | string name = 1; 189 | } 190 | 191 | // The response message containing the greetings. 192 | message HelloReply { 193 | string message = 1; 194 | } 195 | ``` 196 | Greet.proto will be used in .NET core microservice and it has one method to just greet hello {message} 197 | 198 | **Package.json** 199 | We have to install some dependencies to compile these two proto files into pure *.ts file so that our gateway API can understand these contracts.(i.e. methods) 200 | 201 | ``` 202 | npm install @nestjs/microservices 203 | npm install rxjs 204 | npm install ts-proto 205 | ``` 206 | 207 | We are also going to add some scripts to compile the files. 208 | 209 | ``` 210 | "proto:book": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/book/ ../grpc-nest-proto/proto/book.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 211 | "proto:greet": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto -I=../grpc-nest-proto/proto --ts_proto_out=src/greet/ ../grpc-nest-proto/proto/greet.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb", 212 | "proto:all": "npm run proto:book && npm run proto:greet" 213 | ``` 214 | **NOTE:** 215 | If you see some issues running these script and compiling your proto files, then you can download [proto compiler](https://github.com/protocolbuffers/protobuf/releases) and compile your files. 216 | ``` 217 | // here is how i run this commmand in windows powershell 218 | >$nestjs-microservice-gRPC\grpc-nest-proto> ..\protoc-3.20.0-win64\bin\protoc.exe --plugin=./node_modules/.bin/protoc-gen-ts_proto.cmd --ts_proto_out=./build ./proto/*.proto --ts_proto_opt=nestJs=true --ts_proto_opt=fileSuffix=.pb 219 | ``` 220 | 221 | 222 | ### nest.js microservice 223 | 224 | ok, so now we have proto files (i.e. contracts) ready to start with. We are going to make our first microservice using nest.js. 225 | 226 | ***grpc-nest-book-svc*** 227 | ``` 228 | $ cd grpc-nest-book-svc 229 | $ code . 230 | $ npm i @nestjs/microservices @grpc/grpc-js @grpc/proto-loader @nestjs/typeorm typeorm pg class-transformer class-validator 231 | $ npm i -D @types/node ts-proto 232 | $ nest g mo book && nest g co book --no-spec && nest g s book --no-spec 233 | ``` 234 | Now, let's start with bootstrapping- 235 | 236 | ***main.ts*** 237 | ``` 238 | async function bootstrap() { 239 | const app = await NestFactory.createMicroservice(BookModule, { 240 | transport: Transport.GRPC, 241 | options: { 242 | url: '0.0.0.0:50051', 243 | protoPath: './../grpc-nest-proto/proto/book.proto', 244 | package: 'book', 245 | }, 246 | }); 247 | 248 | // tslint:disable-next-line: no-console 249 | app.listen(); 250 | } 251 | ``` 252 | ***books.mocks.ts*** 253 | 254 | Add dummy mock data for books - [mock books data](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/grpc-nest-book-svc/src/books.mock.ts) 255 | 256 | ***book.controller.ts*** 257 | 258 | ``` 259 | @Controller('book') 260 | export class BookController { 261 | constructor(private readonly bookService: BookService) {} 262 | 263 | @GrpcMethod('BookService','getBooks') 264 | @Get() 265 | async getBooks(getBooksRequest): Promise { 266 | return { books: await this.bookService.getBooks() } 267 | } 268 | 269 | @GrpcMethod('BookService','getBookById') 270 | @Get(':id') 271 | async getBookById(id:number): Promise { 272 | return {book: await this.bookService.getBookById(id)} 273 | } 274 | } 275 | ``` 276 | 277 | ***book.service.ts*** 278 | ``` 279 | import { getBooksResponse,Book } from '../../grpc-nest-proto/build/proto/book.pb'; 280 | import { Injectable, HttpException } from '@nestjs/common'; 281 | import { GrpcMethod } from '@nestjs/microservices'; 282 | import { BOOKS } from './books.mock'; 283 | 284 | @Injectable() 285 | export class BookService { 286 | books = BOOKS; 287 | 288 | getBooks(): Promise { 289 | return new Promise(resolve => { 290 | resolve(this.books); 291 | }); 292 | } 293 | 294 | getBookById(param): Promise { 295 | 296 | console.log(param); 297 | return new Promise(resolve => { 298 | const book = this.books.find($book => $book.id === param.id); 299 | if (!book) { 300 | throw new HttpException('Book does not exist!', 404); 301 | } 302 | resolve(book); 303 | }); 304 | } 305 | } 306 | ``` 307 | ***Build and Run this microservice*** 308 | ``` 309 | npm run start:dev 310 | ``` 311 | 312 | ***Testing using Postman*** 313 | ![Book service testing](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/grpc-nest-book-svc/images/bookservicetesting.png) 314 | 315 | 316 | 317 |

(back to top)

318 | 319 | 320 | ### ASP.NET Core microservice 321 | ***prerequisite*** 322 | 323 | [C# for VSCode -optional if you use .NET IDE](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) 324 | 325 | [.NET 6.0 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) 326 | 327 | ***Create new project*** 328 | ``` 329 | dotnet new grpc -o aspnetcore-api 330 | dotnet dev-certs https --trust 331 | ``` 332 | 333 | Here is how we are going to use our **SayHello** contract from greet.proto file 334 | ``` 335 | public override Task SayHello(HelloRequest request, ServerCallContext context) 336 | { 337 | return Task.FromResult(new HelloReply 338 | { 339 | Message = "Hello " + request.Name 340 | }); 341 | } 342 | ``` 343 | ***Important files to check or take a look*** 344 | ``` 345 | Program.cs 346 | Appsettings.json 347 | proto/greet.proto (same as our generic grpc-nest-proto folder. You can even refer it from there) 348 | ``` 349 | 350 | ***Testing using Postman*** 351 | ![Greet service testing](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/aspnetcore-api/images/greetservicetesting.png) 352 | 353 | 354 |

(back to top)

355 | 356 | 357 | ### nest.js API Gateway 358 | 359 | API Gateway is going to communicate with both of our microservices. It will be regular http based API which will handle request and responses to/from these microservices. It will use gRPC communication channel to talk to these microservices. 360 | 361 | Gateway will have two sub-module 362 | - Book 363 | - controller.ts' 364 | - This will have basic request and response middle man method 365 | - module.ts 366 | - This is where we are going to consume that nest.js book service on grpc channel 367 | - book.pb.ts (compiled book.proto file) 368 | - Greet 369 | - controller.ts 370 | - module.ts 371 | - This is where we are going to consume that asp.net greet service on grpc channel 372 | - greet.pb.ts (compiled greet.proto file) 373 | 374 | 375 | ***Testing using Postman*** 376 | ![Greet service testing](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/grpc-nest-api-gateway/images/greetservicetesting.png) 377 | 378 | ![Book service testing](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example/blob/master/grpc-nest-api-gateway/images/bookservicetesting.png) 379 | 380 | 381 | 382 | ## Resources 383 | * https://docs.nestjs.com/microservices/grpc#sample-grpc-service 384 | * https://levelup.gitconnected.com/nestjs-microservices-with-grpc-api-gateway-and-authentication-part-1-2-650009c03686 385 | * https://levelup.gitconnected.com/nestjs-microservices-with-grpc-api-gateway-and-authentication-part-2-2-d67dc8e3b86a 386 | * https://mariobuonomo.dev/blog/tutorial-nestjs-microservices-grpc 387 | * https://medium.com/effective-development/building-grpc-api-in-nest-with-typescript-95e1915abc15 388 | * https://www.codemag.com/Article/2212071/A-Deep-Dive-into-Working-with-gRPC-in-.NET-6 389 | 390 | 391 |

(back to top)

392 | 393 | 394 | 395 | 396 | ## Contributing 397 | 398 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 399 | 400 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 401 | Don't forget to give the project a star! Thanks again! 402 | 403 | 1. Fork the Project 404 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 405 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 406 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 407 | 5. Open a Pull Request 408 | 409 |

(back to top)

410 | 411 | 412 | 413 | 414 | ## License 415 | 416 | Distributed under the MIT License. See `LICENSE.txt` for more information. 417 | 418 |

(back to top)

419 | 420 | 421 | 422 | 423 | ## Contact 424 | 425 | Bhavin Patel 426 | 427 | [Wordpress](http://itsmebhavin.wordpress.com/) - [LinkedIn](https://www.linkedin.com/in/bhavin-patel-55691310/) 428 | 429 | Project Link: [https://github.com/itsmebhavin/nestjs-microservices-gRPC-example](https://github.com/itsmebhavin/nestjs-microservices-gRPC-example) 430 | 431 |

(back to top)

432 | 433 | 434 | 435 | --------------------------------------------------------------------------------