Logo de NestJS

NestJS

Comandos

Instalar NestJS CLI
npm install -g @nestjs/cli

Ver version de NestJS CLI
nest --version ó nest -v

Crear un nuevo proyecto
nest new project-name

Crear una clase
nest g class class-name ó nest g cl class-name

Crear un controlador
nest g controller controller-name ó nest g co controller-name

Crear un servicio
nest g service service-name ó nest g s service-name

Crear un módulo
nest g module module-name ó nest g mo module-name

Crear un recurso (controlador, servicio, módulo, DTO y entidad)
nest g resource resource-name ó nest g res resource-name

Crear un pipe
nest g pipe pipe-name ó nest g pi pipe-name

Crear un guard
nest g guard guard-name ó nest g gu guard-name

Generar el build de producción
npm run build

Conceptos

Si no se pone el modificador de acceso a una propiedad o método, por defecto es público.

Archivos principales

Módulos

Los módulos son una forma de organizar la aplicación en bloques. Un módulo agrupa elementos relacionados, como componentes, controladores, servicios, etc.

Controladores

Se encargan de las rutas, son responsables de manejar las solicitudes entrantes y devolver las respuestas al cliente.

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseIntPipe,
  Patch,
  Post
} from '@nestjs/common';
import { CarsService } from './cars.service';

// indica que este controlador se encargará de las rutas que comiencen con /cars
@Controller('cars')
export class CarsController {
  constructor(private readonly carsService: CarsService) {}

  // indica que este método se encargará de las peticiones GET a la ruta /cars
  // si no se especifica el decorador @Get() se asume que es un GET
  // si hay dos métodos con el mismo decorador y la misma ruta, se ejecuta el primero
  @Get()
  getAllCars() {
    return this.carsService.findAll();
  }

  // indica que este método se encargará de las peticiones GET a la ruta /cars/:id
  // @Param() obtener el parámetro id de la ruta
  // ParseIntPipe convierte el parámetro id en un número entero
  @Get(':id')
  getCarById(@Param('id', ParseIntPipe) id: number) {
    return this.carsService.findOneById(id);
  }

  // indica que este método se encargará de las peticiones POST a la ruta /cars
  // @Body() obtener el cuerpo de la petición
  @Post()
  createCar(@Body() body: any) {
    return body;
  }

  // indica que este método se encargará de las peticiones PATCH a la ruta /cars/:id
  // @Param() obtener el parámetro id de la ruta
  @Patch(':id')
  updateCar(@Param('id', ParseIntPipe) id: number, @Body() body: any) {
    return body;
  }

  // indica que este método se encargará de las peticiones DELETE a la ruta /cars/:id
  // @Param() obtener el parámetro id de la ruta
  @Delete(':id')
  deleteCar(@Param('id', ParseIntPipe) id: number) {
    return {
      method: 'delete',
      id
    };
  }
}

Servicios

Los servicios son clases que contienen la lógica de negocio de la aplicación de manera que sea reutilizable mediante inyección de dependencias. Se encargan de la comunicación con la base de datos, de la lógica de negocio, etc.
Los servicios se pueden inyectar en los controladores, en otros servicios, en los módulos, etc.
Los servicios son singletons, es decir, solo hay una instancia de cada servicio en la aplicación.
Todos los servicios son providers, pero no todos los providers son servicios.

import { Injectable, NotFoundException } from '@nestjs/common';

@Injectable()
export class CarsService {
  private cars = [
    {
      id: 1,
      brand: 'Toyota',
      model: 'Corolla'
    },
    {
      id: 2,
      brand: 'Honda',
      model: 'Civic'
    }
  ];

  findAll() {
    return this.cars;
  }

  findOneById(id: number) {
    const car = this.cars.find((car) => car.id === id);
    if (!car) throw new NotFoundException(`Car with id '${id}' not found`);

    return car;
  }
}

Pipes

Transforman los datos recibidos en la petición para que se ajusten al tipo de dato que espera el controlador.
Algunos pipes son:

También se pueden crear una nueva instancia del pipe para pasarle otros parametros. ej: new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE })

import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { CarsService } from './cars.service';

@Controller('cars')
export class CarsController {
  constructor(private readonly carsService: CarsService) {}

  @Get(':id')
  getCarById(@Param('id', ParseIntPipe) id: number) {
    return this.carsService.findOneById(id);
  }
}

Exception filters

Los exception filters se encargan de manejar las excepciones que se producen en la aplicación. Maneja los errores de código en mensajes de respuesta http. Nest incluye casos comunes pero se pueden expandir para manejar casos específicos.
Algunos exception filters son:

DTO

Los DTO (Data Transfer Object) son objetos que se utilizan para transferir datos entre diferentes capas de la aplicación.
Los DTO se utilizan para validar los datos que se reciben en las peticiones.

Se pueden utilizar los decorators de class-validator para validar los datos. Se puede pasar un objeto de opciones al decorator para personalizar la validación.

import { IsNotEmpty, IsNumber, IsString } from 'class-validator';

export class CreateCarDto {
  @IsNotEmpty()
  @IsString()
  brand: string;

  @IsNotEmpty()
  @IsString()
  model: string;

  @IsNotEmpty()
  @IsNumber()
  year: number;
}

Para validar los pipes de manera global se puede definir la configuración en el archivo main.ts.

import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // indica que la aplicación usará un ValidationPipe para validar los datos de entrada
  /* whitelist: true indica que solo se aceptarán los datos que estan definidos en el DTO,
  los demás serán ignorados */
  /* forbidNonWhitelisted: true indica que si se envía un dato que no está definido en el DTO
  se lanzará un error */
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true
    })
  );

  await app.listen(3000);
}
bootstrap();