Logo
Empezar a leer

© 2025 - alckordev

Versionado de APIs con NestJS

1 agosto, 2025

4 minutos de lectura

0

Versionado de APIs con NestJS

El versionado de una API permite evolucionar tu backend sin romper clientes que consumen endpoints antiguos. NestJS ofrece soporte nativo para varios esquemas de versionado, como URI, Encabezado (header) y Media Type (Accept header). En esta guía:

  1. Instalaremos NestJS y crearemos un proyecto.
  2. Habilitaremos el versionado global (URI).
  3. Veremos ejemplos de controladores/v1 y controladores/v2.
  4. Exploraremos otros esquemas (header, media type).
  5. Recomendaciones de estructura y buenas prácticas.

1. Instalación de NestJS CLI

Si no lo tienes instalado aún, instala el CLI global de NestJS:

npm i -g @nestjs/cli
nest --version

2. Crear el proyecto

Genera un nuevo proyecto:

nest new my-api
cd my-api

Instala dependencias básicas (opcional):

npm install @nestjs/config

3. Habilitar versionado global

Abre src/main.ts y configura lo siguiente:

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { VersioningType } from "@nestjs/common";

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

  // Global prefix "api"
  app.setGlobalPrefix("api");

  // Enable URI versioning: /api/v{version}/{route}
  app.enableVersioning({
    type: VersioningType.URI,
    prefix: "v",
    defaultVersion: "1",
  });

  await app.listen(3000);
  console.log(`Listening on http://localhost:3000/api/v1/...`);
}
bootstrap();
  • type: URI / HEADER / MEDIA_TYPE / CUSTOM
  • prefix: prefijo usado en el URI (v)
  • defaultVersion: versión cuando no se especifica

4. Estructura de carpetas por versión

Para mantener claridad, organiza módulos, controladores y servicios según la versión:

src/
├── api/
│   ├── v1/
│   │   ├── products/
│   │   │   ├── products.module.ts
│   │   │   ├── products.controller.ts
│   │   │   └── products.service.ts
│   └── v2/
│       └── products/
│           ├── products.module.ts
│           ├── products.controller.ts
│           └── products.service.ts
└── app.module.ts

5. Ejemplo: Controlador y Servicio v1

Genera módulo, servicio y controlador:

nest g module api/v1/products
nest g service api/v1/products
nest g controller api/v1/products

src/api/v1/products/products.controller.ts:

import { Controller, Get } from "@nestjs/common";
import { ProductsService } from "./products.service";

@Controller({ path: "products", version: "1" })
export class ProductsController {
  constructor(private readonly service: ProductsService) {}

  @Get()
  findAll() {
    return this.service.findAll();
  }
}

src/api/v1/products/products.service.ts:

import { Injectable } from "@nestjs/common";

@Injectable()
export class ProductsService {
  findAll() {
    return [{ id: 1, name: "Product V1" }];
  }
}

6. Ejemplo: Controlador y Servicio v2

Genera módulo, servicio y controlador:

nest g module api/v2/products
nest g service api/v2/products
nest g controller api/v2/products

src/api/v2/products/products.controller.ts:

import { Controller, Get } from "@nestjs/common";
import { ProductsService } from "./products.service";

@Controller({ path: "products", version: "2" })
export class ProductsController {
  constructor(private readonly service: ProductsService) {}

  @Get()
  findAll() {
    // New structure or extra fields in V2
    return this.service
      .findAll()
      .map((p) => ({ ...p, description: "Added  in V2" }));
  }
}

src/api/v2/products/products.service.ts:

import { Injectable } from "@nestjs/common";

@Injectable()
export class ProductsService {
  findAll() {
    return [{ id: 1, name: "Product V2", description: "" }];
  }
}

Ahora al llamar:

  • GET /api/v1/products → devuelve [{ id: 1, name: 'Product V1' }]
  • GET /api/v2/products → devuelve [{ id: 1, name: 'Product V2', description: 'Added in V2' }]

7. Otros esquemas de versionado

a. Versionado por encabezado (HEADER)

app.enableVersioning({
  type: VersioningType.HEADER,
  header: "X-API-Version",
  defaultVersion: "1",
});

El cliente incluirá: X-API-Version: 2

b. Versionado por media type (Accept header)

app.enableVersioning({
  type: VersioningType.MEDIA_TYPE,
  key: "v", // Accept: application/json;v=2
  defaultVersion: "1",
});

c. Versionado personalizado (CUSTOM)

app.enableVersioning({
  type: VersioningType.CUSTOM,
  factory: (request) => {
    // extract version from cookie or query param
    return request.headers["api-version"] || "1";
  },
});

8. Buenas prácticas y recomendaciones

  • Mantén versiones limpias: archiva o retira V1 cuando ya no sea necesaria.
  • Prueba ambas versiones usando herramientas como Postman o e2e tests.
  • Evita breaking changes innecesarios: usa versiones mayores (v2→v3) sólo cuando sea imprescindible.

¡Con esto ya tienes tu API versionada apoyándote en las capacidades nativas de NestJS! Ahora podrás evolucionar tus endpoints sin miedo a romper integraciones existentes.

test...

¿Te gustó lo que leíste?

Si lo deseas, puedes apoyarme con una donación voluntaria. Tu aporte me permite dedicar más tiempo a investigar, escribir y mejorar la calidad del contenido que publico. ¡Muchísimas gracias por considerar impulsar este proyecto!

Cómprame un café

Compartir en:

Versionado de APIs con NestJS - Isco • Desarrollador de software