Service Template - infranestjs
This template service is designed to facilitate the developer in setting up a new service and includes within it most of the software requirements of vcita.
We used NestJS as framework, A progressive Node.js framework for building efficient, reliable and scalable server-side applications.
What does it include? Example for notes service with single entity with all needed features (Shown below)
Table of contents:
Pre-reqs
To build and run this app locally you will need a few things:
Getting started
Clone the repository
git clone git@github.com:vcita/nestjs-service-template.git
Install dependencies
For better code editor auto-complete:
cd <project_name>
npm install
Define your module
You must define a module with the base requirements to support all features that described below Features.
Example: src/notes/notes.module.ts
.
Then import your module in the src/app.module.ts
.
Run the app
You can run the app with its dependencies (RedisDB, MySQL) using docker compose:
$ docker-compose up
By default, the app running in watch mode, You can modify it in the Dockerfile.
Optional Run commands:
$ npm run start
$ npm run start:dev
$ npm run start:prod
Features
Http Controllers
The controllers are based on decorators that defined the controller's functionality and also the swagger (As described below).
The controller (src/notes/controllers/notes.controller.ts
) demonstrates how to implement CRUD actions with decorators that also served the swagger.
For more details visit here
DB
Database is configured by default.
TypeORM chosen as ORM library, it supports multiple types of DBs (including NoSQL DBs).
The template works with TypeORM based on repository design pattern.
Initialize your data
- Define your entity:
For example src/notes/note.entity.ts
(Make sure that you are using the correct decorators).
You must extend src/infra/repositories/base.entity.ts
for getting all base data that we need. - Define your repository API:
For example src/notes/notes.repository.ts
.
You must extend src/infra/repositories/base.repository.ts
- Get into the container shell
- Generate initial migration:
npm run typeorm -- migration:generate -n <YOUR_MIGRATION_NAME>
- auto-generating migration from your entity definition, read more - Run migrations:
npm run typeorm -- migration:run
- read more
- From now on, for any entity changes you need to repeat steps 3 - 5 to auto generating migration and run it.
- All migration will be placed on the migration directory (In the root directory)
main port 48388
worker port <service_port_worker>
swagger name <swagger_name>
Additional information
Open API (Swagger)
Open API configured by default, swagger UI served at route /swagger-ui
.
In the bootstrap function (In main.ts) you can edit the base data of the swagger document.
Swaggers are building using decorators.
For more details visit here.
HTTP Timeout
The template using interceptor to handle application timeouts through app global interceptor.
By default, the timeout for any request configured to 100 milliseconds and return RequestTimeoutException if needed.
The timeout interceptor implementation - timeout.interceptor.ts .
Additional information:
Logger
The template contains a default logger service: src/infra/services/infra-logger.service.ts
.
Infra logger service parse all data that we need for our infrastructure service (Kibana for example).
The template also including a middleware logger that logged all HTTP requests: src/infra/middlewares/logger.middleware.ts
.
For more details visit here.
Metrics - Prometheus
The chosen library for metrics is NestJS Prometheus.
By default, this will register a /metrics
endpoint that will return the default metrics.
To inject costume metrics see Injecting individual metrics section
Health & Readiness
NestJS supplies a library which gives the ability to expose health checks and readiness.
Basic health check already implemented as part if the template:
- Route: /health
- Checks: availability, DB connection
For more details visit here.
Task Scheduling
Declare a cron job with the @Cron() decorator preceding the method definition containing the code to be executed.
For example:
src/notes/notes.service.ts#triggerNoteNotifications
src/app.service.ts#handleAppCronInterval
For more details visit here
Workers - Consumer & Producers
Nest provides the @nestjs/bull package as an abstraction/wrapper on top of Bull, a popular, well supported, high performance Node.js based Queue system implementation.
The package makes it easy to integrate Bull Queues in a Nest-friendly way to your application.
Example:
-
Queue registration:
Set your queue's name in the as environment variable in the .env
file:
REDIS_QUEUES=<queue_name>,<queue_name>
For example: REDIS_QUEUES=notes,note_secondary_queue
or REDIS_QUEUES=notes
.
Register your queues in your module (See example in src/notes/notes.module.ts
):
const queues: BullModuleOptions[] = process.env.REDIS_QUEUES.split(',').map(
function (queue) {
return { name: queue };
},
);
BullModule.registerQueue({
name: 'notes',
})
-
Injection:
(See example in src/notes/services/notes.service.ts
)
@InjectQueue('notes') private readonly queue: Queue
-
Define queue metrics:
In the constructor of the service that injected the queue set (must be imported from infra library):
applyBullMetrics(queue)
-
Producing (See example in src/notes/notes.service.ts
):
await this.newNoteQueue.add('new_note', note);
-
Consuming (See example in src/notes/notes.processor.ts
):
@Process('new_note')
async notifier(job: Job<Note>) {
const note: Note = job.data;
const msg = `Processing job ${job.id} of type ${job.name} with data ${JSON.stringify(note)}`;
this.logger.infraLog(msg);
}
You can produce messages to the queue with different name (As we did with the 'new_note') and to consume it in different process @Process('new_note')
.
For more information visit here.
Publish Message to core RabbitMQ
TBD
Authentication
TBD
Test
Unit tests
$ npm run test
or from outside the container
$ docker exec -it <CONTAINER_NAME> npm run test
E2E tests
$ npm run test:e2e
or from outside the container
$ docker exec -it <CONTAINER_NAME> npm run test:e2e
Test coverage
$ npm run test:cov
or from outside the container
$ docker exec -it <CONTAINER_NAME> npm run test:cov
Template development
If you are interested in developing directly on the template you need to initialize the following variables:
Service base data:
infranestjs
48388
<context_name>
Database' credentials:
<database_type>
<database_host>
<database_port>
<database_name>
<database_user>
<database_password>
Redis' credentials:
<redis_host>
<redis_port>
<redis_port>
OAuth's credentials:
<oauth_redirect_uri>
<oauth_client_secret>
<oauth_client_id>
<oauth_server>
<api_gw_server>