A Quick and Easy Guide to Version Your API in NestJS

📅August 17, 2023

🕒6 minute read

🏷

nodejs

nestjs

These days, when you google "How to do x?" in anything related to software engineering you usually expect a comprehensive resource that you can follow to end up doing "x". Well, when I looked up how to version my API in NestJS, I came up short for the most part. Most results were just too overly-complicated. Versioning shouldn't be complicated, so here's my take on what would've helped me the most.

Why Version Your API?

API versioning is essential for maintaining a stable and reliable ecosystem for both API developers and users. It enables you to make changes to your API throughout it's lifetime. Changes such as adding new features or modifying existing functionality, without disrupting existing client applications. This helps pave way to smooth transitions for API consumers.

URL Versioning

One common approach to versioning an API is by incorporating the version number into the URL. This allows for clear differentiation between different API versions. Examples of this can look like the following:

  • slack.com/api/v1/channels.list (v1)
  • discord.com/api/v10/guilds/{guild.id}/members/{user.id} (v10)
  • api.twitter.com/2/tweets/{tweetId} (2)
  • shopify.com/admin/api/2023-08/orders.json (2023-08)

URL versioning also happens to be very straightforward. You make any breaking changes to an endpoint, that means you update the version on a newly created controller (versioned controllers). Keep it simple, stupid.

Implementing URL Versioning

In your main.ts file add enableVersioning config to app.

// ...

app.enableVersioning({
  type: VersioningType.URI, // eg '/api/v1'
});

Note: The version in the URI will be automatically prefixed with v by default, however the prefix can be configured by setting the prefix key.

Then add versioning to your controller/s.

// ... 
@Controller({ path: 'auth', version: '1' })
@ApiTags('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('login')
  login(@Body() { email, password }: LoginDto) {
    return this.authService.login(email, password);
  }
}

This results in your endpoint being exposed as something like: localhost:8000/api/v1/auth/login.

As seen on line 1, you can use any type of string to represent your version naming scheme.

Behold, we have versioning! 🎉

In the future, lets say the AuthController changes drastically for some reason. You can create a new controller and assign a new version to it.

// ...
@Controller({ path: 'auth', version: '2' })
@ApiTags('auth')
export class AuthControllerV2 {
// ...

Note: The same can be done on individual controller functions.

That's literally all you need if you want URL versioning on your NestJS app. If that's what you wanted, stop reading, implement your own URL versioning now and ignore the rest of this article.

Other Types of Versioning

Besides URL versioning, there's a few more ways to implement, but they only serve very specific use-cases which most of us probably won't need, so you can just stick to URL versioning, like Slack and Discord do.

For information's sake, this is what the other versioning strategies can do.

  • Header versioning
    • Allows clients to dynamically switch between different versions by simply changing the request headers. This can be useful when clients need to interact with multiple versions simultaneously or switch versions without modifying the URL.
  • Query-Param Versioning
    • Can be advantageous when dealing with caching mechanisms. Different versions of the same resource can be cached separately, and cache keys can include the version parameter, ensuring accurate caching for each version.
  • Dynamic Module Loading
    • For APIs with a large number of endpoints or complex routing requirements, dynamic module loading can help maintain a more organized and modular codebase. Each version can be encapsulated within its own module, making it easier to manage and extend.

For these more complicated use-cases, the NestJS docs are the best resource available.

Peace✌️