Fullstack NestJS

NestJS Framework Tour


The Goal

To understand the role that the major components play within the NestJS framework.

The TLDR Tour

The linear explaination goes in this order.

  1. The Entry File
  2. The Module
  3. The Controller
  4. The Service

The conceptual explanation goes in this order.

  1. The Controller
  2. The Service
  3. The Module
  4. The Entry File

I will give a one sentence explaination of each in the linear order and you can read about the more in the conceptual order below.

The entry file file (main.ts) is responsible for configuring and creating your application using NestFactory.

A module is an organizational mechanism that registers other components such as controllers and service in the application so they can be configured at runtime.

A controller is a lightweight class that exposes an endpoint to a user as well as the various routes that are available to that endpoint.

A service is responsible for processing work delegated by the controller such as business logic or interacting with the data layer.

The Controller

The contoller exposes a route using the @Controller() decorator and is required for every controller. The decorate takes single parameter which will serve as the prefix for the exposed route.

@Controller('challenges')
export class ChallengesController { }

This will now create a challenges route for the application.

You can then define various route handlers using the available decorators.

@Controller('challenges')
export class ChallengesController {
  @Post()
  create(@Body() challenge: Challenge): Promise<Challenge> {}

  @Get()
  findAll(): Promise<Challenge[]> {}

  @Get(':id')
  findOne(@Param('id') id: string): Promise<Challenge> {}

  @Patch(':id')
  update(@Param('id') id: string, @Body() challenge: Challenge) {}

  @Delete(':id')
  remove(@Param('id') id: string) {}
}

There will register five routes that match with HTTP RESTful conventions.

Nest uses dependency inejction like Angular to provide dependencies to consuming classes. Because we want our controllers to be lightweight, we can inject a service for the controller to delegate "real work" towards.

In this case, we are injecting the ChallengesService as a parameter into the contructor and because we added an access modifier, TypeScript will automatically assing it as a member of the class. This is why we can invoke the service using this.challengesService in the create method.

@Controller('challenges')
export class ChallengesController {
  constructor(private readonly challengesService: ChallengesService) {}

  @Post()
  create(@Body() challenge: Challenge): Promise<Challenge> {
    return this.challengesService.create(challenge);
  }

  //...
}

You can also control the access to routes with the UseGuards decorator which creates a route guard based on guard you provide it.

As an advanced topic, you can also create custom decorators using Reflector.createDectorator. This allows us to create a custom Roles decorator that serves as a route guard based on the role of the authenticated user making the request.

@Controller('challenges')
export class ChallengesController {
  constructor(private readonly challengesService: ChallengesService) {}

  @Post()
  create(@Body() challenge: Challenge): Promise<Challenge> {
    return this.challengesService.create(challenge);
  }

  @Get()
  @Roles(['tester'])
  @UseGuards(JwtAuthGuard, RolesGuard)
  findAll(): Promise<Challenge[]> {
    return this.challengesService.findAll();
  }

}

The Service

The Module

Each application has a top-level module and usually one or more feature modules.

The Entry File

< Nest Home