DEV Community

Dilum Darshana
Dilum Darshana

Posted on β€’ Edited on

1

What You Need to Know Before Starting a NestJS Project

Hello Backend devs...

NestJS has quickly become one of the most popular Node.js progressive frameworks for building scalable and maintainable server-side applications. The patterns are followed by Angular's architecture and fully support with TypeScripts. NestJS brings structure and strong typing to the fast-paced world of REST API developments.

If you're coming from Express or a similar minimal framework, starting a NestJS project can feel like a big shiftβ€”in a good way. Its modular design, built-in dependency injection, and clear separation of concerns promote clean code and make it easier to scale your application as it grows.

In this guide, I will walk you through the most important concepts you need to know before starting your NestJS project (I am talking about V11.X)

🟒 Main building blocks

  • Modules - Group together everything
  • Controller - Handle incoming request
  • Services - Handle business logic
  • Pipes - Validate incoming data
  • Exception Filters - Handle errors throws by controller or service
  • Guards - Handle authentication and authorisation. Can decide request proceed to not (return true / false)
  • Interceptors - Adding extra data to request or to response
  • Middleware - Can modify request object
  • Repositories - Handle data stored in DB

🟒 The main architecture

NestJS does not handle HTTP request itself. We need to provide either Express OR Fastify for handling HTTP requests. By default, NestJS uses Express.

NestJS Server

NestJS main building blocks has an order of execution. See bellow,

Flow of execution

🟒 DI Container

NestJS uses dependency injection (DI) as its main design pattern for the easy management of dependencies between application components. NestJS DI system is based on the Inversion of Control (IoC) technique, meaning that the framework controls the creation and life cycle of an objects (such as services and controllers) rather than the objects themselves controlling these aspects.

Basically, NestJS helps with automatically creating and injecting services and other dependencies into classes; hence, one can decouple components and keep the application modular.

🟒 Interceptors

This can be used to modify request and response. Let's say want to modify the request object before it goes to the controller,

Create a new interceptor in the correct module. Eg. modules -> auth -> interceptors -> auth.interceptor.ts

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class OAuthInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();

    // transform user profile
    if (request.user) {
      request.user = this.normalizeUserProfile(); // modify user object
    }

   return next.handle(); // just return the request object without modifying response object
  }
}
Enter fullscreen mode Exit fullscreen mode

Note that the return next.handle();. It just pass the request to the controller, no change on response.

Next, call the interceptor from controller,

@UseGuards(AuthGuard('github'))
@UseInterceptors(OAuthInterceptor)
async githubAuthCallback(@Req() req: AuthenticatedRequest, @Res() res: Response) {
  if (!req.user) {
      throw new UnauthorizedException('User not authorized');
  }
}
Enter fullscreen mode Exit fullscreen mode

If it's need to modify the response,

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, map } from 'rxjs';

@Injectable()
export class OAuthInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();

    // transform user profile
    if (request.user) {
      request.user = this.normalizeUserProfile(); // modify user object
    }

    // modify the response also,
    return next.handle().pipe(
      map((data) => {
        return {
          success: true, // add anything additional
          data,
        }
      })
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

🟒 Final Thoughts

It is vital to understand the basic concepts before start any new technologies. It is may be take some time, but, hold on, it would be a good investment for the future. I will update the post with the new finding continuously.

🀝 Let's meet again with setting up NestJS app. Click Here

Cheers... Happy coding!!!

Top comments (0)