NestJS tiene varias características principales que lo hacen muy eficiente y modular. A continuación, se presentan algunas de estas características junto con ejemplos de código para una mejor comprensión:
Los controladores son responsables de manejar las solicitudes entrantes y devolver las respuestas al cliente. En NestJS, un controlador es simplemente una clase que se anota con el decorador @Controller
.
import { Controller, Get } from '@nestjs/common';
@Controller('tasks')
export class TasksController {
@Get()
findAll() {
return 'This action returns all tasks';
}
}
En el ejemplo anterior, TasksController
tiene una única ruta manejada por el método findAll()
. Esta ruta manejará las solicitudes GET a '/tasks'.
Los proveedores en NestJS son una forma amplia de decir servicios, repositorios, fábricas, helpers, etc. Un proveedor es simplemente una clase que NestJS puede instanciar e inyectar en otras clases como dependencias.
import { Injectable } from '@nestjs/common';
@Injectable()
export class TasksService {
private readonly tasks: string[] = ['Task 1', 'Task 2', 'Task 3'];
findAll(): string[] {
return this.tasks;
}
}
El servicio TasksService
en este ejemplo tiene un método findAll()
que devuelve una lista de tareas.
Los módulos son una forma efectiva de organizar tus componentes en unidades cohesivas. Cada aplicación tiene al menos un módulo, el módulo raíz. Puedes generar tantos módulos como necesites con nest g module module_name
.
import { Module } from '@nestjs/common';
import { TasksController } from './tasks.controller';
import { TasksService } from './tasks.service';
@Module({
controllers: [TasksController],
providers: [TasksService],
})
export class TasksModule {}
El TasksModule
en este ejemplo es un módulo que declara TasksController
y TasksService
.
Los middlewares en NestJS son equivalentes a los middleware de Express. Se utilizan para ejecutar código antes de que los manejadores de ruta manejen la solicitud.
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { TasksController } from './tasks.controller';
import { TasksService } from './tasks.service';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
@Module({
controllers: [TasksController],
providers: [TasksService],
})
export class TasksModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes(TasksController);
}
}
En este ejemplo, LoggerMiddleware
se aplica a todas las rutas manejadas por TasksController
.
El LoggerMiddleware
es un ejemplo de middleware en NestJS. En general, un middleware es un componente que se coloca en el medio del flujo de una solicitud HTTP, es decir, entre la recepción de una solicitud HTTP y la respuesta que se envía. Puede hacer varias cosas, como modificar la solicitud y la respuesta, finalizar el ciclo de solicitud/respuesta, invocar la siguiente middleware en la pila, entre otras cosas.
En el contexto de este ejemplo, LoggerMiddleware
podría ser un middleware que registra información sobre cada solicitud HTTP que recibe la aplicación, como la ruta de la solicitud, el método HTTP, la IP del cliente, el cuerpo de la solicitud, y demás.
Un ejemplo simple de un LoggerMiddleware
en NestJS podría ser el siguiente:
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request details:', req.method, req.url, req.ip);
next();
}
}
En este ejemplo, LoggerMiddleware
imprime los detalles de cada solicitud HTTP que recibe la aplicación antes de pasar la solicitud al siguiente middleware o controlador.
Los pipes son clases anotadas con el decorador @Injectable()
, que implementan la interfaz PipeTransform
. Se utilizan para transformar o validar datos en las solicitudes entrantes.
import { Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class ValidationPipe implements PipeTransform<any> {
transform(value: any) {
if (!value) {
throw new Error('Value should not be null or undefined');
}
return value;
}
}
En este ejemplo, ValidationPipe
valida que el valor de la solicitud no esté vacio.
Los Guards
son una de las características de NestJS que se utilizan para implementar la lógica de autorización / autenticación antes de que se ejecute una ruta o un controlador. Un Guard
en NestJS es una clase que implementa la interfaz CanActivate
.
A continuación se presenta un ejemplo simple de un Guard
:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
// Get the request object
const request = context.switchToHttp().getRequest();
// Implement your authentication logic here.
// For instance, you can check if the request headers have a valid authentication token.
// Return true if the request is authenticated, or false otherwise.
return validateRequest(request);
}
}
Para utilizar este guard, simplemente se añade al controlador o a la ruta específica:
@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {
// ...
}
En este caso, antes de que cualquier ruta en CatsController
se ejecute, NestJS primero llamará a la función canActivate()
del AuthGuard
. Si canActivate()
devuelve true
, entonces se ejecuta la ruta. Si canActivate()
devuelve false
, entonces NestJS bloqueará la solicitud y enviará una respuesta HTTP 403 al cliente.
Los Interceptors
son otra característica de NestJS que permiten interceptar las solicitudes y respuestas HTTP, proporcionando una forma de manejar aspectos como la transformación de la respuesta, la manipulación de los errores, el registro de la actividad de la red, la implementación de la caché, etc.
A continuación se presenta un ejemplo simple de un Interceptor
:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
return next
.handle()
.pipe(
map(data => ({ data })),
);
}
}
Para utilizar este interceptor, simplemente se añade al controlador o a la ruta específica:
@UseInterceptors(TransformInterceptor)
@Controller('cats')
export class CatsController {
// ...
}
En este caso, TransformInterceptor
intercepta la respuesta del controlador y la transforma, envolviendo el contenido de la respuesta en un objeto { data: ... }
.