En este tutorial vas a crear tu primera aplicacion backend usando Nestjs, el Framework de Backend de Nodejs.

Instalación de Nestjs

npm i -g @nest/cli

Creación del Proyecto

nest new nestfirstapp

Limpiando Proyecto

Elimina archivos como:

  • app.controller.spect.ts
  • app.controller.ts
  • app.service.ts

dejando la siguiente estructura:

src
├── app.module.ts
└── main.ts

y dejando el main.ts, de la siguiente form:

@Module({
  imports: [],
  controllers: [],
  providers: [],
})
export class AppModule {}

Creando Modulo de Tareas

Luego crearemos un modulo de tareas con su respectivo controlador y servicios.

nest g module tasks
nest g controller tasks --no-spec
nest g service tasks --no-spec

Creando Task Entity

src/tasks/tasks.entity.ts:

export enum TaskStatus {
  OPEN = 'OPEN',
  IN_PROGRESS = 'IN_PROGRESS',
  DONE = 'DONE',
}

export class Task {
  id: string;
  title: string;
  description: string;
  status: TaskStatus;
}

Creando el Servicio de Tareas

import { Injectable } from '@nestjs/common';
import { Task, TaskStatus } from './task.entity';

@Injectable()
export class TasksService {
  private tasks: Task[] = [];

  getAllTasks(): Task[] {
    return this.tasks;
  }

  createTask(title: string, description: string): Task {
    const task = {
      id: new Date().toISOString(),
      title,
      description,
      status: TaskStatus.OPEN,
    };

    this.tasks.push(task);
    return task;
  }

  getTaskById(id: string): Task {
    return this.tasks.find((task) => task.id === id);
  }

  deleteTask(id: string): void {
    this.tasks = this.tasks.filter((task) => task.id !== id);
  }

  updateTask(id: string, updatedFields: any): Task {
    const task = this.getTaskById(id);
    const newTask = Object.assign(task, updatedFields);
    this.tasks = this.tasks.map((task) => (task.id === id ? newTask : task));
    return newTask;
  }

  updateTaskStatus(id: string, status: TaskStatus): Task {
    const task = this.getTaskById(id);
    task.status = status;
    return task;
  }
}

Creando DTO

src/tasks/task.dto.ts

import { TaskStatus } from './task.entity';

export class CreateTaskDto {
  title: string;
  description: string;
}

export class UpdateTaskDto {
  title: string;
  description: string;
  status: TaskStatus;
}

Actualizar servicio

  createTask(newTask: CreateTaskDto): Task {
    const task = {
      id: new Date().toISOString(),
      title: newTask.title,
      description: newTask.description,
      status: TaskStatus.OPEN,
    };

    this.tasks.push(task);
    return task;
  }


  updateTask(id: string, updatedFields: UpdateTaskDto): Task {
    const task = this.getTaskById(id);
    const newTask = Object.assign(task, updatedFields);
    this.tasks = this.tasks.map((task) => (task.id === id ? newTask : task));
    return newTask;
  }

Crear controlador

import{
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  Patch,
  Post,
} from '@nestjs/common';
import { CreateTaskDto, UpdateTaskDto } from './task.dto';
import { TasksService } from './tasks.service';

@Controller('tasks')
export class TasksController {
  constructor(private tasksService: TasksService) {}

  @Get()
  getAllTasks() {
    return this.tasksService.getAllTasks();
  }

  @Post()
  createTask(@Body() newTask: CreateTaskDto) {
    return this.tasksService.createTask(newTask);
  }

  @Get(':id')
  getTaskById(@Param('id') id: string) {
    return this.tasksService.getTaskById(id);
  }

  @Delete(':id')
  @HttpCode(204)
  deleteTask(@Param('id') id: string) {
    return this.tasksService.deleteTask(id);
  }

  @Patch(':id')
  updateTask(@Param('id') id: string, @Body() updatedFields: UpdateTaskDto) {
    return this.tasksService.updateTask(id, updatedFields);
  }
}

Validaciones

import { TaskStatus } from './task.entity';
import { IsNotEmpty, IsOptional, IsIn } from 'class-validator';

export class CreateTaskDto {
  @IsNotEmpty()
  title: string;

  @IsNotEmpty()
  description: string;
}

export class UpdateTaskDto {
  @IsOptional()
  title: string;

  @IsOptional()
  description: string;

  @IsOptional()
  @IsIn([TaskStatus.OPEN, TaskStatus.IN_PROGRESS, TaskStatus.DONE])
  status: TaskStatus;
}

main.ts:

  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,
  }));