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.