Hola a todos, hoy os voy a explicar como podemos crear un CRUD de forma sencilla en nestjs.
Un CRUD (Create Read Update Delete) nos ofrecen las operaciones básicas para gestionar un grupo de elementos ya sea en NestJS u otro sistema backend.
Creación de un proyecto en NestJS
Sino sabes como crear tu proyecto en NestJs, te dejamos un manual:
Creación CRUD
Una vez creado nuestro proyecto, abrimos la terminal y escribimos el siguiente comando:
Nos preguntará que capa de transporte usar, en nuestro caso elegiremos REST API
Después, nos preguntará si queremos crear los entry points, esto lo veremos en el fichero controller, le decimos que si.
Nos crea en la carpeta users con la siguiente estructura:
El fichero user.controller.ts ya contiene los entry points que probaremos después.
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() create(@Body() createUserDto: CreateUserDto) { return this.usersService.create(createUserDto); } @Get() findAll() { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string) { return this.usersService.findOne(+id); } @Patch(':id') update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(+id, updateUserDto); } @Delete(':id') remove(@Param('id') id: string) { return this.usersService.remove(+id); } }
El fichero user.module.ts ya contiene todo importado:
import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; @Module({ controllers: [UsersController], providers: [UsersService] }) export class UsersModule {}
El fichero user.service.ts le tenemos que dar nosotros la lógica, esto lo haremos después.
Entidades
La entidad a gestionar será usuarios, por lo que vamos a añadir propiedades a la clase de User del fichero user.entity.ts
export class User { // Identificador del usuario id: number; // Nombre del usuario name: string; // Email del usuario email: string; }
Los dtos son clases que reciben los entry points en el controller, antes de tocar estas clases, vamos a instalar lo siguiente:
La dependencia class-validator nos permite validar propiedades de nuestros dtos y class-transformer transforma un objeto a dto.
Veamos como validar un dto:
import { IsPositive, IsEmail, IsNotEmpty, IsOptional } from "class-validator"; export class CreateUserDto { @IsPositive() // Valido si es positivo @IsOptional() // No es obligatorio de incluir id?: number; @IsNotEmpty() // Es obligatorio de incluir name: string; @IsNotEmpty() // Es obligatorio de incluir @IsEmail() // Debe tener un formato de email email: string; }
¿Con esto es suficiente? No, en el fichero main.ts, se debe agregar la siguiente linea, después de crear app, quedando asi:
import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // Todos los endpoints seran validados app.useGlobalPipes(new ValidationPipe( { transform: true })) await app.listen(3000); } bootstrap();
Miremos la clase UpdateUserDto:
import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; export class UpdateUserDto extends PartialType(CreateUserDto) {}
Ese extends PartialType(CreateUserDto) lo que hace es coger las propiedades del usuario y las convierte a todas en opcionales.
Dando lógica a nuestro servicio
Ya con todo esto que tenemos, podemos volver al fichero user.service.ts.
Crearemos un array de objetos que utilizaremos como mock y rellenar la lógica de las funciones. Ojo, esto es un ejemplo, puede variar según lo que se necesite.
import { ConflictException, Injectable } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { User } from './entities/user.entity'; @Injectable() export class UsersService { // Datos private users: User[] = [ { id: 1, name: 'Fernando', email: 'fernando@gmail.com' }, { id: 2, name: 'Alberto', email: 'alberto@gmail.com' }, { id: 3, name: 'Miguel', email: 'miguel@gmail.com' }, ]; // Simulamos un autoincrement private autoIncrement: number = 4; /** * Crea un usuario * @param createUserDto * @returns */ create(createUserDto: CreateUserDto) { // obtenemos el id que nos dan en createUserDto let id = createUserDto.id // sino existe el id, lo autoincrementamos if(!id){ id = this.autoIncrement++; }else{ // El id existe // Comprobamos si el id existe if(this.users.find(u => u.id == id)){ throw new ConflictException('El id ya existe'); } this.autoIncrement = id + 1; } // Comprobamos si el email existe if(this.users.find(u => u.email == createUserDto.email)){ throw new ConflictException('El email ya existe'); } // Creamos el usuario const user = { id, name: createUserDto.name, email: createUserDto.email }; // añadimos el usuario al array this.users.push(user); // devolvemos el usuario return user; } /** * Devolvemos todos los usuarios * @returns */ findAll() { return this.users; } /** * Devolvemos un usuario dado un id * @param id * @returns */ findOne(id: number) { return this.users.find(user => user.id == id); } /** * Actualizamos un usuario * @param id * @param updateUserDto * @returns */ update(id: number, updateUserDto: UpdateUserDto) { // Buscamos si el usuario existe let user = this.users.find(user => user.id == id); if(user){ // Compruebo si el nuevo id existe, evitamos la comprobacion del propio usuario a editar if(updateUserDto.id && this.users.find(user => user.id != id && user.id == updateUserDto.id)){ throw new ConflictException('El id ya existe'); } // Compruebo si el nuevo email existe, evitamos la comprobacion del propio usuario a editar if(updateUserDto.email && this.users.find(user => user.id != id && user.email == updateUserDto.email)){ throw new ConflictException('El email ya existe'); } // Modificamos el id si viene en el objeto updateUserDto, sino le dejamos el que original user.id = updateUserDto.id ? updateUserDto.id : user.id; // Modificamos el name si viene en el objeto updateUserDto, sino le dejamos el que original user.name = updateUserDto.name ? updateUserDto.name : user.name; // Modificamos el email si viene en el objeto updateUserDto, sino le dejamos el que original user.email = updateUserDto.email ? updateUserDto.email : user.email; // Devuelve el usuario return user; } return null; } /** * Eliminamos un usuario dado un id * @param id * @returns */ remove(id: number) { // Buscamos el id de un usuario let userIndex = this.users.findIndex(user => user.id == id); // Si existe lo borramos con splice if(userIndex != -1){ this.users.splice(userIndex, 1); return true; } return false; } }
Arrancar proyecto NestJS
Ahora, arrancamos el proyecto con el siguiente comando:
Probar endpoints con Postman
Si pones http://localhost:3000 en el navegador, deberías ver esto:
Solo nos falta probar el resto de entry points, para ello, os recomiendo el programa postman, lo puedes descargar aquí.
Te dejo aquí un fichero con todos los entry points para importarlos. En la parte de arriba veras un botón para importarlos, solo arrastra el fichero y tendrás algo como esto:
Probamos cada uno de ellos:
Te lo dejo en video:
Te dejo un repositorio en github con todo lo visto.
Espero que os sea de ayuda. Si tenéis dudas, preguntad. Estamos para ayudarte.
Deja una respuesta