NashTech Blog

Introduction

Nest.js continues to gain popularity in the world of Node.js development, thanks to its powerful features and intuitive design. In this blog post, we’ll explore advanced techniques and best practices to take your Nest.js applications to the next level. From dependency injection to interceptors and guards, let’s dive into the intricacies of Nest.js development with code examples.


Let’s dive in
  • Mastering Dependency Injection: Nest.js embraces the concept of dependency injection (DI) to facilitate modular and maintainable application development. With DI, components are provided with their dependencies rather than creating them directly. This promotes reusability and testability while reducing coupling between components.In the example provided, we have a CatsService that encapsulates the logic for managing cat data. By decorating the CatsService class with @Injectable(), we indicate to Nest.js that this class can be injected as a dependency into other components. In the CatsController, we inject the CatsService using constructor injection and utilize its methods to handle incoming requests.Let’s look at an example:

// cats.service.ts
import { Injectable } from ‘@nestjs/common’;

@Injectable()
export class CatsService {
private readonly cats: string[] = [‘Meow’, ‘Purr’, ‘Hiss’];

findAll(): string[] {
return this.cats;
}
}

Inject the CatsService into a controller:

// cats.controller.ts
import { Controller, Get } from ‘@nestjs/common’;
import { CatsService } from ‘./cats.service’;

@Controller(‘cats’)
export class CatsController {
constructor(private readonly catsService: CatsService) {}

@Get()
findAll(): string[] {
return this.catsService.findAll();
}
}

  • Interceptors for Cross-Cutting Concerns: Interceptors are middleware components that allow you to intercept incoming requests and outgoing responses. They enable you to implement cross-cutting concerns such as logging, caching, and error handling in a modular and reusable manner.In the example, we define a LoggingInterceptor that implements the NestInterceptor interface. This interceptor intercepts incoming requests, logs the current timestamp before processing the request, and logs the elapsed time after processing. By applying the LoggingInterceptor using the @UseInterceptors() decorator, we can apply this logging logic to specific controllers or methods.

// logging.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from ‘@nestjs/common’;
import { Observable } from ‘rxjs’;
import { tap } from ‘rxjs/operators’;

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const now = Date.now();
console.log(`Before… ${now}`);

return next
.handle()
.pipe(
tap(() => console.log(`After… ${Date.now() – now}ms`)),
);
}
}

Apply the interceptor to a controller or method:

// app.controller.ts
import { Controller, Get, UseInterceptors } from ‘@nestjs/common’;
import { LoggingInterceptor } from ‘./logging.interceptor’;

@UseInterceptors(LoggingInterceptor)
@Controller()
export class AppController {
@Get()
getHello(): string {
return ‘Hello World!’;
}
}

  • Guards for Authorization: Guards provide a mechanism for protecting routes from unauthorized access by implementing access control logic. They can be used to enforce authentication, authorization, or any custom access control requirements.In the example, we define an AuthGuard that implements the CanActivate interface. This guard checks whether the incoming request is authorized based on custom validation logic implemented in the validateRequest() function. By applying the AuthGuard using the @UseGuards() decorator, we restrict access to the CatsController to only authenticated users.

// auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from ‘@nestjs/common’;
import { Observable } from ‘rxjs’;

@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}

Apply the guard to a controller or method:

// cats.controller.ts
import { Controller, Get, UseGuards } from ‘@nestjs/common’;
import { AuthGuard } from ‘./auth.guard’;

@UseGuards(AuthGuard)
@Controller(‘cats’)
export class CatsController {
@Get()
findAll(): string[] {
return [‘Meow’, ‘Purr’, ‘Hiss’];
}
}

Conclusion

With these advanced techniques and best practices, you can build robust and scalable Nest.js applications. Whether you’re managing dependencies, intercepting requests, or implementing authorization logic, Nest.js provides the tools you need to create high-quality applications. Keep exploring the capabilities of Nest.js and stay ahead in the world of Node.js development.

Checkout the code here – GitHub

For more detail checkout the NestJS documentation.

With these thank you if you were there till the end. For more such blogs and updates follow Front-end Competency.

Follow NashTech Blogs for more amazing blogs.

Scroll to Top