Implementar el repository pattern en NestJS con TypeORM transforma la forma en que tu aplicación se conecta a la base de datos: en lugar de manejar arrays en memoria, delegas todo el CRUD a una clase que opera directamente sobre la entidad. Esta guía te muestra cómo refactorizar un servicio para usar este patrón, resolver errores comunes de inyección y validar tu API con Postman.
¿Qué es el repository pattern y por qué usarlo en NestJS?
El repository pattern es un patrón de diseño que centraliza toda la lógica de acceso a datos a través de una entidad. En vez de escribir consultas manuales o mantener arrays en memoria, inyectas un repository tipado que ya trae métodos como find, findOneBy, save, merge y delete listos para usar.
¿Qué hace exactamente un repository en TypeORM? Es una clase genérica que recibe tu entidad como tipo y expone métodos para consultar, crear, actualizar y eliminar registros sin escribir SQL directamente.
La ventaja es doble: tu servicio queda más limpio y, al estar fuertemente tipado, el editor te avisa si pasas un string donde se espera un number [02:45].
¿Cómo inyectar un repository en un servicio?
La inyección se hace con dos piezas: el decorador @InjectRepository del paquete @nestjs/typeorm y la clase Repository de typeorm. En el constructor del servicio importas tu entidad y la pasas al decorador.
typescript
constructor(
@InjectRepository(User) private usersRepository: Repository<User>,
) {}
Un detalle importante: si tu modelo anterior y tu entidad comparten nombre, vas a tener un choque de imports. Borra la interfaz vieja y deja solo la entidad.
¿Por qué falla NestJS con "cannot resolve dependencies"?
Cuando arrancas la aplicación tras inyectar el repository, NestJS suele lanzar un error diciendo que no puede resolver UserRepository. La causa es que el módulo no sabe qué entidades exponer para el patrón.
La solución es declararlas explícitamente en el módulo correspondiente:
typescript
imports: [TypeOrmModule.forFeature([User, Profile])]
Con forFeature le dices al módulo qué entidades pueden usar el repository pattern, y TypeORM aprovecha esa declaración para crear las tablas con su esquema antes de operar [12:30].
¿Cómo refactorizar los métodos del servicio paso a paso?
La refactorización implica volver asíncronos casi todos los métodos, porque cada llamada al repository devuelve una Promise. Aquí va el desglose por operación.
¿Cómo buscar uno o varios registros con findOne y find?
Para traer todos los registros usas this.usersRepository.find(), que internamente ejecuta un select sin where. Si quieres filtrar, le pasas un objeto con condiciones.
Para buscar por ID, el método ideal es findOneBy:
typescript
const user = await this.usersRepository.findOneBy({ id });
if (!user) throw new NotFoundException('Usuario no existe');
return user;
¿Cuál es la diferencia entre create y save en TypeORM?
Esta es una de las dudas más frecuentes y vale la pena tenerla clara desde el principio.
¿Create o save en TypeORM? create solo instancia el objeto en memoria siguiendo el patrón orientado a objetos, pero no toca la base de datos. save es el que realmente persiste el registro. Para insertar, siempre usa save.
¿Cómo actualizar registros con merge?
En vez de usar el spread operator para mezclar el usuario existente con los cambios, el repository ofrece merge, que respeta los valores anteriores y solo sobrescribe los nuevos:
typescript
this.usersRepository.merge(user, changes);
return this.usersRepository.save(user);
Es más seguro y más legible que armar el objeto manualmente.
¿Cómo convertir parámetros de URL en números con ParseIntPipe?
Cualquier param o query param llega como string, porque la URL no distingue tipos. Si tu entidad espera un number, necesitas transformarlo antes de pasarlo al servicio.
La forma rápida es prefijar el valor con +, pero NestJS ofrece algo más robusto: ParseIntPipe. Este pipe valida que el valor sea un entero válido, rechaza negativos mal formados y aplica una expresión regular más estricta.
typescript
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
Simplemente importa ParseIntPipe desde @nestjs/common y déjale al pipe la conversión [09:15].
¿Cómo manejar errores de duplicidad y excepciones en el create?
Si tu columna email tiene una restricción de unicidad y alguien intenta registrar un correo repetido, Postgres devuelve un duplicate key y NestJS responde con un 500 que tumba la experiencia.
La solución es envolver el save en un try/catch y lanzar una excepción controlada:
typescript
try {
return await this.usersRepository.save(newUser);
} catch (error) {
throw new BadRequestException('Hubo un error al crear el usuario');
}
¿Por qué no decirle al usuario que el email ya existe? Revelar que un correo está registrado puede ser un riesgo de seguridad, porque permite a un atacante validar cuentas existentes. Mejor responde con un mensaje genérico.
Así pasas de un 500 que rompe la app a un 400 controlado que mantiene el servidor estable.
¿Qué validaciones agregar en el DTO al cambiar la entidad?
Al modificar la entidad User para que tenga email y password en vez de name, el DTO también debe alinearse. Para password conviene exigir un mínimo de ocho caracteres como restricción básica de seguridad.
@IsEmail() para validar el formato del correo.
@IsString() y @MinLength(8) para el password.
@IsOptional() en el DTO de actualización si el password no es obligatorio.
Las columnas id, created_at y updated_at se autogeneran, así que nunca deberías enviarlas desde el cliente ni manejarlas en el servicio.
¿Cómo verificar que las tablas se crearon correctamente?
Usa un cliente gráfico como pgAdmin o DataGrip para revisar el esquema. Tras correr la app por primera vez, refresca la conexión y deberías ver las tablas users y profiles con sus columnas: id, email, password, created_at, updated_at.
Un detalle a vigilar es el naming: si tu propiedad en la entidad se llama lastName pero olvidas pasarle el name al decorador @Column, la columna en la base de datos quedará como lastName en vez de last_name. Revisa esos detalles en el diagrama gráfico antes de seguir.
Cuéntame en los comentarios qué método del repository te resultó más útil al refactorizar tu propio servicio.