Saltar a contenido

Desarrollo de Servicios – NestJS Backend

Pautas específicas para microservicios construidos con NestJS.

Stack recomendado

  • Runtime: Node.js 20+
  • Framework: NestJS 10+
  • Lenguaje: TypeScript
  • ORM: TypeORM (preferido)
  • Base de datos: PostgreSQL
  • Documentación: Swagger/OpenAPI

Estructura de proyecto

backend/
├── src/
│   ├── config/           # Configuración centralizada
│   ├── modules/          # Módulos de dominio (users, products, etc.)
│   ├── common/           # Código compartido (decorators, guards, filters...)
│   ├── database/         # Migraciones y seeds
│   ├── app.module.ts
│   ├── app.controller.ts
│   ├── app.service.ts
│   └── main.ts
├── test/
├── Dockerfile
├── Makefile
├── package.json
├── env.example
└── README.md

Configuración centralizada (ConfigService)

Archivo src/config/configuration.ts:

export const configuration = () => ({
  nodeEnv: process.env.NODE_ENV || 'development',
  database: {
    type: 'postgres' as const,
    host: process.env.DATABASE_HOST || 'postgres',
    port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
    username: process.env.DATABASE_USER || 'postgres',
    password: process.env.DATABASE_PASSWORD || 'postgres',
    database: process.env.DATABASE_NAME || 'app_db',
    synchronize: process.env.NODE_ENV !== 'production',
    logging: process.env.NODE_ENV === 'development',
  },
  auth: {
    jwtSecret: process.env.JWT_SECRET || 'change_me_in_production',
  },
  logging: {
    level: process.env.LOG_LEVEL || 'info',
  },
});

Uso en AppModule:

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        ...config.get('database'),
        entities: ['dist/**/*.entity{.ts,.js}'],
        migrations: ['dist/database/migrations/*{.ts,.js}'],
      }),
    }),
    // otros módulos de dominio
  ],
})
export class AppModule {}

Bootstrap y Swagger

En main.ts:

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

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
      transformOptions: { enableImplicitConversion: true },
    }),
  );

  const config = new DocumentBuilder()
    .setTitle('API Backend')
    .setDescription('API del ecosistema')
    .setVersion('1.0')
    .addBearerAuth()
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api/docs', app, document);

  app.enableCors({
    origin: process.env.CORS_ORIGIN || '*',
  });

  await app.listen(3000);
}

bootstrap();

Health check y logging

  • Exponer /health como endpoint simple.
  • Usar Logger de NestJS o un wrapper para logs estructurados.
@Controller('health')
export class HealthController {
  @Get()
  health() {
    return { ok: true };
  }
}

Migraciones y base de datos

  • Mantener migraciones en src/database/migrations.
  • Ejecutar migraciones desde scripts de npm o Makefile.
  • Nunca usar synchronize en producción.

Buenas prácticas

  • Separar módulos por dominio (no monolitos de un solo módulo gigante).
  • Usar DTOs en controllers para todo input externo.
  • Encapsular lógica de negocio en servicios, no en controllers.
  • Manejar excepciones con filtros globales o interceptores.