Skip to main content

Api Versioning In Nestjs

· 5 min read
Sivabharathy

When building APIs, managing different versions is critical for backward compatibility and feature updates. NestJS provides built-in support for API versioning, allowing developers to handle multiple versions of APIs gracefully.

This article explores API versioning in NestJS, its types, and how to implement them with examples.


Why API Versioning?​

API versioning helps manage changes in your application without breaking functionality for existing clients. It ensures:

  • Smooth transitions between versions.
  • Backward compatibility for older API clients.
  • Clear separation of new features or deprecations.

Enabling Versioning in NestJS​

NestJS allows versioning to be enabled globally using the enableVersioning() method. The versioning strategies available are:

  1. URI Versioning
  2. Header Versioning
  3. Media Type Versioning
  4. Custom Versioning

1. URI Versioning​

In URI versioning, the version is part of the API path, typically prefixed with v (e.g., /v1/resource).

Enable URI Versioning​

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

app.enableVersioning({
type: VersioningType.URI, // Version is specified in the URL.
defaultVersion: "1", // Sets a default version.
});

Defining Versioned Routes​

import { Controller, Get, Version } from "@nestjs/common";

@Controller("users")
export class UsersController {
@Get()
@Version("1") // Handler for version 1
getUsersV1() {
return { message: "This is version 1 of the users API" };
}

@Get()
@Version("2") // Handler for version 2
getUsersV2() {
return { message: "This is version 2 of the users API" };
}
}

Requests​

  • GET /v1/users → { message: 'This is version 1 of the users API' }
  • GET /v2/users → { message: 'This is version 2 of the users API' }

2. Header Versioning​

In header versioning, the version is specified in a custom HTTP header, such as X-API-Version.

Enable Header Versioning​

app.enableVersioning({
type: VersioningType.HEADER, // Version is specified in headers.
header: "X-API-Version", // Custom header name.
});

Defining Versioned Routes​

@Controller("users")
export class UsersController {
@Get()
@Version("1") // Handler for version 1
getUsersV1() {
return { message: "This is version 1 of the users API" };
}

@Get()
@Version("2") // Handler for version 2
getUsersV2() {
return { message: "This is version 2 of the users API" };
}
}

Requests​

  • GET /users with header X-API-Version: 1 → { message: 'This is version 1 of the users API' }
  • GET /users with header X-API-Version: 2 → { message: 'This is version 2 of the users API' }

3. Media Type Versioning​

In media type versioning, the API version is included in the Accept header, such as application/vnd.myapp.v1+json.

Enable Media Type Versioning​

app.enableVersioning({
type: VersioningType.MEDIA_TYPE, // Version is in Accept header.
});

Defining Versioned Routes​

@Controller("users")
export class UsersController {
@Get()
@Version("1") // Handler for version 1
getUsersV1() {
return { message: "This is version 1 of the users API" };
}

@Get()
@Version("2") // Handler for version 2
getUsersV2() {
return { message: "This is version 2 of the users API" };
}
}

Requests​

  • GET /users with header Accept: application/vnd.myapp.v1+json → { message: 'This is version 1 of the users API' }
  • GET /users with header Accept: application/vnd.myapp.v2+json → { message: 'This is version 2 of the users API' }

4. Custom Versioning​

NestJS also supports custom strategies for versioning. You can define your own logic by implementing the VersioningOptions.

Custom Versioning Example​

import { VersioningOptions, VersioningType } from "@nestjs/common";

app.enableVersioning({
type: VersioningType.CUSTOM, // Use custom versioning logic.
extractor: (request) => {
// Extract version from a query parameter, cookie, etc.
return request.query["version"] || "1";
},
});

Defining Versioned Routes​

@Controller("users")
export class UsersController {
@Get()
@Version("1") // Handler for version 1
getUsersV1() {
return { message: "This is version 1 of the users API" };
}

@Get()
@Version("2") // Handler for version 2
getUsersV2() {
return { message: "This is version 2 of the users API" };
}
}

Requests​

  • GET /users?version=1 → { message: 'This is version 1 of the users API' }
  • GET /users?version=2 → { message: 'This is version 2 of the users API' }

Default Version​

If no version is provided in the request, the defaultVersion option specifies which version to use. This ensures backward compatibility for older clients.

Example:​

app.enableVersioning({
type: VersioningType.URI,
defaultVersion: "1", // Default to version 1
});

Request to /users (without version) will be mapped to /v1/users.


Combining Versioning Types​

NestJS allows you to combine multiple versioning strategies for more flexibility. For example, you can use both URI and Header versioning.

Example:​

app.enableVersioning({
type: [VersioningType.URI, VersioningType.HEADER],
});

Conclusion​

API versioning in NestJS provides a powerful and flexible mechanism to manage multiple API versions. With strategies like URI, Header, Media Type, and Custom versioning, you can choose the approach that best suits your application’s requirements. By enabling versioning, you ensure backward compatibility and scalability as your application evolves.


By following this guide, you can implement robust versioning in your NestJS application to handle changes and updates efficiently.