How to add a route prefix to specific modules using NestJS?
Asked Answered
K

4

12

I want to add routing prefixes at the module level and/or have complex global routing prefix logic in general.

I know I can use the undocumented function NestApplication.setGlobalPrefix to set a single global prefix:

// main.ts
app.setGlobalPrefix(version);

However, I want to set prefixes at the module level in this case.

It appears I could achieve this by setting my desired prefix into the decorators at the controller level:

//controler.ts
@Get('/PREFIX/health')
async getHealth() {

  // TODO: implement
  return {};
}

But this seems fairly hacky and error-prone. Surely there is a better way?

Keshiakesia answered 16/11, 2020 at 19:52 Comment(0)
K
18

Update 2021

NestJS now supports the original answer natively.

In addtion, NestJS v8 also adds more sophisticated routing when the primary function is versioning an API:

@Controller({
  path: 'cats',
  version: '1', // 👈
})
export class CatsController {
...

Original Answer

The most robust way to accomplish this in NestJS is to use the nest-router package to create a routing tree.

yarn add nest-router
# or npm i nest-router

Create a file next to main.ts called routes.ts like so:

import { Routes } from 'nest-router';
import { YourModule } from './your/your.module';

export const routes: Routes = [
  {
    path: '/v1',
    module: YourModule,
  },
];

Then, inside your app.module.ts file, add the router before any other modules are loaded:

@Module({
  imports: [
    RouterModule.forRoutes(routes),
    YourModule,
    DebugModule
  ],

})

Now when you navigate to YourModule controller, all of its routes will be prefixed with e.g. v1 in this case:

curl http://localhost:3000/v1/your/operation

Using this approach gives you the most flexibility as each module does not need to know how it will be prefixed; the application can decide at a higher level. Almost more advanced prefixes can be computed dynamic versus relying on a static string.

Keshiakesia answered 16/11, 2020 at 19:52 Comment(1)
It seems package is outdated.Spa
U
3

For me, adding a third party package just to achieve this would be a bit unnecessary, let alone the risk of it being outdated/unmaintained. You can add your custom route prefix in the Controller class instead.

  @Controller('custom/prefix')
  export const MyController {

     @Get('health')
     getHealth() {
       //this route would be: custom/prefix/health
       return {};
     }

     @Get('other')
     getOther() {
       //this route would be: custom/prefix/other
       return {};
     }
  }

Then just simply add this controller inside your Module

Undulant answered 20/5, 2021 at 18:18 Comment(0)
R
2

You can now use either the RouterModule configuration or you can exclude some paths from the global prefix configuration (or mix both):

RouterModule: https://docs.nestjs.com/recipes/router-module#router-module

Global prefix "exclude": https://docs.nestjs.com/faq/global-prefix#global-prefix

Rutherfurd answered 22/9, 2021 at 11:44 Comment(0)
F
0
  1. Create the decorator you want for a module.
import { applyDecorators, Controller } from '@nestjs/common'

export function SystemController(path: string) {
  return applyDecorators(Controller(`system/${path}`))
}
  1. Setup decorator in your module.
// system/action module example
import { BaseController } from 'src/shared/providers/base.controller'
import { ActionsService } from './actions.service'
import { Action } from './entities/action.entity'
import { SystemController } from 'src/shared/decorators'

@SystemController('actions')
export class ActionsController extends BaseController<Action> {
  constructor(private readonly actionsService: ActionsService) {
    super(actionsService)
  }
}

Frigid answered 6/8 at 5:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.