{"id":15554927,"url":"https://github.com/wandersonalves/generator-kube-microservice-node","last_synced_at":"2025-07-27T19:05:58.354Z","repository":{"id":48024605,"uuid":"149489152","full_name":"WandersonAlves/generator-kube-microservice-node","owner":"WandersonAlves","description":"A node micro-service generator with TypeScript, mongoose, express, rabbitMQ and others. Also k8s support","archived":false,"fork":false,"pushed_at":"2022-12-02T21:40:08.000Z","size":964,"stargazers_count":27,"open_issues_count":5,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-23T20:19:19.389Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WandersonAlves.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-19T17:41:10.000Z","updated_at":"2023-01-24T16:21:54.000Z","dependencies_parsed_at":"2023-01-22T23:00:39.638Z","dependency_job_id":null,"html_url":"https://github.com/WandersonAlves/generator-kube-microservice-node","commit_stats":null,"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WandersonAlves%2Fgenerator-kube-microservice-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WandersonAlves%2Fgenerator-kube-microservice-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WandersonAlves%2Fgenerator-kube-microservice-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WandersonAlves%2Fgenerator-kube-microservice-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WandersonAlves","download_url":"https://codeload.github.com/WandersonAlves/generator-kube-microservice-node/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250506147,"owners_count":21441723,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T15:04:58.001Z","updated_at":"2025-04-23T20:19:36.966Z","avatar_url":"https://github.com/WandersonAlves.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# generator-kube-microservice-node\n[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors)\n\n[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)\n\nA yeoman generator for nodejs micro services with TypeScript, Express, Mongoose, Redis and RabbitMQ.\n\n## Why?\n\nThis project is a boilerplate for extensible micro services written in TypeScript.\nContains the minimum to instant deploy a service on a Kubernetes Cluster.\n\n## Contents\n\nThis template contains:\n\n- TypeScript\n- Dockerfile\n- Kubernetes deployment configuration (including `Service` k8s object)\n- TypeScript definition for mongo operators on controller functions\n- `MongoService` abstract class for all entities services\n- `GenericException` base for all exceptions\n- `withException` decorator to abstract error handling logic (used on generated controllers)\n- `RemoteController` class to handle `axios` requets\n- `RabbitMQ` consumers and producers logic\n- `expressjs` implementation with `inversifyjs` and `inversify-express-utils`\n\n## Install\n\n- `npm i -g yo`\n- `npm i -g generator-kube-microservice-node`\n- `yo kube-microservice-node`\n- Follow the inscructions\n\n## How to run\n\n- Run `yarn dev` to spawn a nodemon server watching source files\n- Create a .env file in root to handle all your secrets. Look at `src/config/env.ts` to see the default list of variables\n\n## Usage\n\n### Controllers\n\nControllers of this boilerplate are handled by `inversify-express-utils` package.\n\nHere is a exemple:\n\n```typescript\n@controller('/user')\nexport default class UserController {\n  @inject(REFERENCES.UserService) private userService: UserService;\n\n  @httpGet('/')\n  @withException\n  async getTenants(@response() res: Response) {\n    const result = await this.tenantService.find({ throwErrors: true });\n    res.status(OK).send(result);\n  }\n\n  @httpGet('/:id')\n  @withException\n  async getUser(@response() res: Response, @requestParam('id') id: string) {\n    // Using Redis\n    const [exception, result] = this.redis.withRedis({ key: 'getUser', expires: 10 }, () =\u003e\n      this.userService.findById({ id }),\n    );\n    if (!exception) {\n      return res.status(exception.statusCode).send(exception.formatError())\n    }\n    return res.status(OK).send(result);\n  }\n```\n\nThere's two types of response when using `MongoService`:\n\n- A result using `Either\u003cL, R\u003e`\n- The raw entity\n\nThe two examples are described above.\n\nEverything is injected by `inversify` and the composition root lives in `src/config/inversify.config.ts`. Your entities controllers should be imported on `src/config/inversify.config.ts`, so `inversify-express-utils` can inject your controller on express routes.\n\nInside the composition root, we import all controllers and `inversifyjs` takes care to setup our application (as seen on `src/index.ts`)\n\n### Services\n\nThe service layer extends the `MongoService\u003cT\u003e` which has all methods to handle the mongoose model.\n\n```typescript\nimport { injectable } from 'inversify';\nimport { MongoService } from '../shared/class/MongoService';\nimport { UserInterface } from '../models/UserInterface';\nimport { UserSchema, UserModel } from '../models/UserModel';\n\n@injectable()\nexport default class UserService extends MongoService\u003cUserInterface\u003e {\n  constructor() {\n    /**\n     * MongoService uses the Schema because if you change the default database while using some method from MongoService,\n     * mongoose don't knows how to create the model schema for this non default database, so we help mongoose to do that\n     */\n    super(UserModel, UserSchema);\n  }\n}\n```\n\n\n### Redis\n\nRedis connection occurs when you require redis into another class. Use like this:\n\n```typescript\n@controller('/user')\nexport default class UserController {\n  @inject(REFERENCES.UserService) private userService: UserService;\n  @inject(REFERENCES.RedisController) private redis: RedisController;\n\n  @httpGet('/')\n  @withException\n  async getUsers(@response() res: Response) {\n    const result = await this.userService.find({});\n    res.status(OK).send(result);\n  }\n\n  @httpGet('/:id')\n  @withException\n  async getUser(@response() res: Response, @requestParam('id') id: string) {\n    // This method gets a entry from cache and set it if don't exist\n    const result = this.redis.withRedis({ key: 'getUser', expires: 10 }, () =\u003e\n      this.userService.findById({ id, throwErrors: true }),\n    );\n    if (!result) {\n      throw new EntityNotFoundException({ id });\n    }\n    res.status(OK).send(result);\n  }\n```\n\n### RabbitMQ\n\nTo use a consume/producer function for RabbitMQ, bootstrap the connection on your `Service` like this:\n\n```typescript\n\n@injectable()\nexport default class UserService extends MongoService\u003cUserInterface\u003e {\n\n  @inject(REFERENCES.EventBus) private eventBus: EventEmitter;\n  private _channel: Channel;\n  constructor() {\n    super(UserModel, UserSchema);\n    // Only connect to Rabbit when mongo is connected\n    this.eventBus.on('mongoConnection', this._createRabbitMQChannelAndSetupQueue);\n    // Reconnect to rabbitmq\n    this.eventBus.on('reconnectRabbitMQ', this._createRabbitMQChannelAndSetupQueue);\n  }\n\n  /**\n * Creates a RabbitMQ Channel and setup the queue for this service\n */\n  // Run this function on constructor\n  private async _createRabbitMQChannelAndSetupQueue() {\n    this._channel = await createRabbitMQChannel(env.rabbitmq_url);\n    // Some consumer on ./src/queue/consumers\n    consumeCreateUser(this._channel, this._consumeCreateUser);\n  }\n  /**\n   * RabbitMQ Consumer CREATE_USER Function\n   *\n   * Creates a user\n   * @param payload RabbitMQ ConsumeMessage type.\n   */\n  private _consumeCreateUser = async (payload: ConsumeMessage) =\u003e {\n    const data = JSON.parse(payload.content.toString());\n    /** DO SOMETHING  */\n    this._channel.ack(payload); // sends a acknowledgement\n  };\n}\n\n```\n\nThe producer is straight forward: just call the function that sends something to a queue (ex: `./src/queue/producers/`)\n\n### Exceptions\n\nAll exceptions that are catch by `src/server/middlewares/index.ts`, have `GenericException` as they base.\n\nSo, just continuing throw new errors based on `GenericException.ts` that express will catch and handle. (see `src/shared/exceptions/` folder for default exceptions created)\n\n### Service authorization\n\nIn `src/server/` you can find a `Unauthorized.ts` file that handles authorization logic of this service.\n\nUsing this middleware, you should have another service with endpoint `/auth` that receives a `JWToken` via `Authorization` header.\n\nIf that service responds with 200, you're authorized to procced with your request into this service.\n\nTo use it, just insert into `src/server/ServerFactory.ts` a line containing this middleware\n\n```typescript\nimport * as bodyParser from 'body-parser';\nimport * as compression from 'compression';\nimport * as cors from 'cors';\nimport * as express from 'express';\nimport { RouteNotFoundMiddleware, ExceptionMiddleware } from './middlewares';\nimport Unauthorized from './Unauthorized';\n\nexport default {\n  initExternalMiddlewares(server: express.Application) {\n    server.use(compression());\n    server.use(bodyParser.json());\n    server.use(cors());\n  },\n  initExceptionMiddlewares(server: express.Application) {\n    // New Line!!!\n    server.use(Unauthorized)\n    server.use(RouteNotFoundMiddleware);\n    server.use(ExceptionMiddleware);\n  },\n};\n```\n\n### Dependency Injection\n\nThis template uses `inversifyjs` to handle DI with a IoC container.\nThe file that handles that is `src/config/inversify.config.ts`\n\n```typescript\nimport '../entities/User/UserController';\nimport '../shared/middlewares/HealthCheck';\n\nimport { Container } from 'inversify';\n\nimport REFERENCES from './inversify.references';\nimport Connection from '../shared/class/Connection';\nimport UserService from '../entities/User/UserService';\nimport RemoteController from '../shared/class/RemoteController';\n\nconst injectionContainer = new Container({ defaultScope: 'Singleton' });\n\ninjectionContainer.bind(REFERENCES.Connection).to(Connection);\ninjectionContainer.bind(REFERENCES.RemoteController).to(RemoteController);\ninjectionContainer.bind(REFERENCES.UserService).to(UserService);\n\n\nexport default injectionContainer;\n\n```\n\nIf your controller has another class dependency, inject the dependency onto your class like this:\n\n```typescript\nexport default class UserController {\n  @inject(REFERENCES.UserService) private userService: UserService;\n}\n```\n\n## Docker and Kubernetes\n\nTo build a docker image, you have to build the project using `npm run build` and `npm run build:webpack`. Then, use `npm run build:docker`, and to publish, use `npm run publish:docker`. Remember to edit these commands if you use private repos.\n\nThe Kubernetes deployment file (`deployment.yaml`), has a `LivenessProbe` that checks if the route `/health` returns 200. This route, pings to the database. If something goes wrong, your service will be restarted.\n\nThe `Service` object in `deployment.yaml` file expose the `Pod` created by the `Deployment` to the world on port 80 and binding the port 3000 of the `Pod` to it.\n\nAfter configuring, you need to add the `Service` definition in a `ingress` controller of your k8s cluster.\n\nSince this template uses Kubernetes, the `.dockerignore` and `Dockerfile` files **DOESN'T** have a reference to `.env`file (which, also is ignored on `.gitignore` file). The way to go about it is setting a `envFrom` field on `deployment.yaml`.\n\nHere is a example:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: user-service\nspec:\n  replicas: 4\n  selector:\n    matchLabels:\n      app: user-service\n  template:\n    metadata:\n      labels:\n        app: user-service\n    spec:\n      containers:\n      - name: user-service\n        image: \u003csome-image\u003e\n        ports:\n          - containerPort: 3000\n        envFrom:\n        - configMapRef:\n            name: env-config\n        livenessProbe:\n          initialDelaySeconds: 20\n          periodSeconds: 5\n          httpGet:\n            path: /health\n            port: 3000\n```\n\n# Contributing\n\nPR's and new issues are welcome. Anything you think that'll be great to this project will be discussed.\n\n## Development\n\nClone this repo, then, `npm install` and `npm link`. Now you can test this generator locally using `yo` command.\n\n# Acknowledgements\n\nMany thanks for the folks that worked hard on:\n\n- `inversifyjs` (https://github.com/inversify/InversifyJS)\n- `inversify-express-utils` (https://github.com/inversify/inversify-express-utils)\n\nWithout these libs, this boilerplate doesn't exists\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://www.linkedin.com/in/vitor-diego/\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/15676011?v=4\" width=\"100px;\" alt=\"Vitor Die.go\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eVitor Die.go\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/e3Labs/generator-kube-microservice-node/issues?q=author%3Adiegofreemind\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#ideas-diegofreemind\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/Blira\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/43551066?v=4\" width=\"100px;\" alt=\"Bruno Lira\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBruno Lira\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/e3Labs/generator-kube-microservice-node/commits?author=Blira\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#maintenance-Blira\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwandersonalves%2Fgenerator-kube-microservice-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwandersonalves%2Fgenerator-kube-microservice-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwandersonalves%2Fgenerator-kube-microservice-node/lists"}