Registro de usuarios

Intermedio
Nest
Nest
Actualizado: 10/06/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Introducción

Crear un método de registro para crear nuevos usuarios en el backend a nivel de base de datos.

Este método estará en un controlador y será accesible desde el frontend por cualquier usuario no autenticado.

Instalar librerías

Necesitaremos una librería para cifrar las contraseñas de forma segura antes de almacenarlas en la base de datos. bcrypt es un estándar de la industria para esta tarea. También nos aseguraremos de tener class-validator y class-transformer para manejar la validación de los datos entrantes de forma declarativa.

npm install bcrypt class-validator class-transformer @nestjs/mapped-types
# o
yarn add bcrypt class-validator class-transformer @nestjs/mapped-types

Definición de la Entidad User y el Role Enum

Para gestionar nuestros usuarios, necesitamos una entidad User que represente la tabla en la base de datos. También definiremos un Role enum para asignar roles a los usuarios (por ejemplo, USER por defecto).

src/user/role.enum.ts

export enum Role {
    USER = 'user',
    ADMIN = 'admin',
}

src/user/user.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { Role } from './role.enum'; // Asegúrate de que la ruta sea correcta

@Entity('users') // Opcional: especificar el nombre de la tabla
export class User {
    @PrimaryGeneratedColumn()
    id: number;

    @Column({ unique: true })
    email: string;

    @Column()
    password: string;

    @Column({ nullable: true })
    phone: string;

    @Column({ nullable: true })
    addressStreet: string;

    @Column({ nullable: true })
    photoUrl: string;

    @Column({
        type: 'enum',
        enum: Role,
        default: Role.USER,
    })
    role: Role;
}

Creación del DTO (Data Transfer Object) para el Registro

Utilizaremos un DTO (Data Transfer Object) para definir la estructura de los datos que esperamos recibir del cliente al registrar un nuevo usuario. Esto nos permitirá validar los datos automáticamente gracias a class-validator.

src/auth/dto/register.dto.ts

import { IsEmail, IsString, MinLength, IsNotEmpty, IsOptional } from 'class-validator';

export class RegisterDto {
    @IsEmail({}, { message: 'El email debe ser una dirección de correo válida.' })
    @IsNotEmpty({ message: 'El email es un campo requerido.' })
    email: string;

    @IsString({ message: 'La contraseña debe ser una cadena de texto.' })
    @MinLength(6, { message: 'La contraseña debe tener al menos 6 caracteres.' })
    @IsNotEmpty({ message: 'La contraseña es un campo requerido.' })
    password?: string;

    // Puedes añadir más campos opcionales si son parte de tu formulario de registro inicial
    @IsOptional()
    @IsString()
    phone?: string;

    @IsOptional()
    @IsString()
    addressStreet?: string;

    @IsOptional()
    @IsString()
    photoUrl?: string;
}

Creación del Módulo AuthModule

Agruparemos la lógica de autenticación en su propio módulo AuthModule. Este módulo importará TypeOrmModule.forFeature() para registrar la entidad User y hacer que su repositorio esté disponible para nuestros servicios y controladores de autenticación.

src/auth/auth.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { User } from '../user/user.entity'; // Asegúrate de que la ruta sea correcta

@Module({
  imports: [
    TypeOrmModule.forFeature([User]), // Registra la entidad User para este módulo
  ],
  controllers: [AuthController],
  providers: [AuthService],
  // Si AuthService será usado por otros módulos, puedes exportarlo:
  // exports: [AuthService]
})
export class AuthModule {}

Desarrollo del Servicio AuthService (Lógica de Negocio)

La lógica principal para el registro de usuarios (comprobar existencia, cifrar contraseña, guardar en DB) debe residir en un servicio. Esto mantiene tu controlador limpio y la lógica de negocio centralizada y reutilizable.

src/auth/auth.service.ts

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

import { Injectable, ConflictException, InternalServerErrorException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../user/user.entity';
import * as bcrypt from 'bcrypt'; // Importa bcrypt
import { RegisterDto } from './dto/register.dto';
import { Role } from '../user/role.enum';

@Injectable()
export class AuthService {
    constructor(
        @InjectRepository(User)
        private userRepository: Repository<User>,
    ) {}

    async register(registerDto: RegisterDto): Promise<User> {
        const { email, password, ...userData } = registerDto;

        // 1. Comprobar si el email ya está en uso
        const existingUser = await this.userRepository.findOne({ where: { email } });
        if (existingUser) {
            throw new ConflictException('El email ya está registrado.'); // HTTP 409 Conflict
        }

        try {
            // 2. Cifrar la contraseña
            // El 'salt' (número de rondas de hash) recomendado es 10-12
            const hashedPassword = await bcrypt.hash(password, 10);

            // 3. Crear una nueva instancia de usuario
            const newUser = this.userRepository.create({
                email,
                password: hashedPassword,
                role: Role.USER, // Asignar rol por defecto
                ...userData // Añadir otros datos opcionales del DTO
            });

            // 4. Guardar el nuevo usuario en la base de datos
            await this.userRepository.save(newUser);

            // Opcional: eliminar la contraseña antes de devolver el objeto usuario
            delete newUser.password;
            return newUser;

        } catch (error) {
            // Manejo de errores más específico si es necesario (ej. problemas de DB)
            console.error('Error al registrar usuario:', error);
            throw new InternalServerErrorException('Error al registrar el usuario. Por favor, inténtelo de nuevo.');
        }
    }
}

Desarrollo del Controlador AuthController

El controlador AuthController se encarga de recibir las peticiones HTTP y delegarlas al AuthService. Aquí usaremos el decorador @Body() con nuestro RegisterDto.

src/auth/auth.controller.ts

import {
    Controller,
    Post,
    Body,
    HttpCode,
    HttpStatus,
    ConflictException,
    UsePipes,
    ValidationPipe,
} from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterDto } from './dto/register.dto';
import { User } from '../user/user.entity';

@Controller('auth') // Prefijo de ruta para todos los endpoints de este controlador
export class AuthController {
    constructor(private readonly authService: AuthService) { }

    @Post('register')
    @HttpCode(HttpStatus.CREATED) // Retorna un 201 Created si el registro es exitoso
    @UsePipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }))
    async register(@Body() registerDto: RegisterDto): Promise<User> {
        return this.authService.register(registerDto);
    }
}

Importar AuthModule en AppModule

Para que NestJS reconozca y cargue nuestro AuthModule, debemos importarlo en el AppModule (nuestro módulo raíz).

src/app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AuthModule } from './auth/auth.module'; // Importa el AuthModule

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        type: configService.get<'mysql'>('DB_TYPE'),
        host: configService.get<string>('DB_HOST'),
        port: configService.get<number>('DB_PORT'),
        username: configService.get<string>('DB_USERNAME'),
        password: configService.get<string>('DB_PASSWORD'),
        database: configService.get<string>('DB_DATABASE'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'], // Esto detecta todas las entidades
        synchronize: true,
      }),
      inject: [ConfigService],
    }),
    AuthModule, // Añade el AuthModule aquí
  ],
})
export class AppModule { }

Configuración de main.ts para Validación Global

Para que la validación con DTOs funcione automáticamente en toda tu aplicación, debes configurar el ValidationPipe globalmente en tu archivo main.ts.

src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

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

  // Habilita la validación global usando los DTOs y class-validator
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true, // Remueve propiedades del cuerpo de la petición que no están definidas en el DTO
    forbidNonWhitelisted: true, // Lanza un error si hay propiedades no definidas en el DTO
    transform: true, // Transforma los payloads entrantes a instancias del DTO
  }));

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

Probando el Registro de Usuarios

Con esta implementación, puedes probar tu endpoint de registro utilizando herramientas como Postman o Insomnia.

  • Ruta: POST http://localhost:3000/auth/register
  • Cuerpo de la Solicitud (JSON): 
{
  "email": "nuevo.usuario@example.com",
  "password": "miPasswordSeguro123",
  "phone": "123456789",
  "addressStreet": "Calle Falsa 123"
}
  • Si el registro es exitoso, recibirás un 201 Created con los datos del nuevo usuario (sin la contraseña).

  • Si intentas registrar el mismo email dos veces, recibirás un 409 Conflict.

  • Si envías datos inválidos (ej. email mal formado, contraseña corta), recibirás un 400 Bad Request gracias a ValidationPipe.

  • En tu BBDD si la solicitud ha sido exitosa, debería aparecer el nuevo registro:

Aprendizajes de esta lección

  • Crear la entidad User
  • Crear método para recibir datos de registro
  • Verificar que el email a registrar no está ocupado
  • Cifrar la contraseña
  • Crear cuenta de usuario

Completa Nest y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración