55

I need to build an API where most of the routes are prefixed with a common URL part which also has a parameter.

In my specific case, my routes need to look like:

/accounts/:account/resource1/:someParam

/accounts/:account/resource2/:someParam/whatever

/accounts/:account/resource3/

/accounts/:account/resource4/subResource/

and so on..

So ideally I would create a parent route /accounts/:account/ which will contain the children routes (resource1, resource2, resource3, resource4, etc...).

I also need the :account parameter to be accessible from all the children routes.

What is the best way to achieve this with NestJS ?

2

4 Answers 4

25

i think you need this?

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

@Controller('accounts/:account')
export class TestController{

    @Get('resource2/:someParam/whatever')
    arsPW(@Param('account') account, @Param('someParam') someparam){
        console.log(':account/resource2/:someParam/whatever',account,someparam)
        return account+'_'+someparam+'___';
    }

    @Get('resource1/:someparam')
    aRSP(@Param('account') account, @Param('someparam') someparam){
        console.log(':account/resource1/:someParam',account,someparam)
        return account+'_'+someparam;
    }


    @Get()
    getget(){
        console.log('get');
        return 'aaa';
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

this is what I'm currently using, but what if I have many children routes? I don't want to have a single, fat Controller class. Ideally I would be able to create different child routes inside different Controller classes
I have kind of the same controller file. But I am not able to call this API. Am I missing something?
25

Regarding your use case, you might want to take a look at this router module
=> https://github.com/shekohex/nest-router

Following the documentation of this module, you can define your routes like so:

... //imports
const routes: Routes = [
    {
      path: '/ninja',
      module: NinjaModule,
      children: [
        {
          path: '/cats',
          module: CatsModule,
        },
        {
          path: '/dogs',
          module: DogsModule,
        },
      ],
    },
  ];

@Module({
  imports: [
      RouterModule.forRoutes(routes), // setup the routes
      CatsModule,
      DogsModule,
      NinjaModule
      ], // as usual, nothing new
})
export class ApplicationModule {}

Of course, the routes would be defined in a separate file like routes.ts

Given the fact you have a controller by module, the previous code would end in the following tree of routes:

ninja
    ├── /
    ├── /katana
    ├── cats
    │   ├── /
    │   └── /ketty
    ├── dogs
        ├── /
        └── /puppy

Example: If you want to reach the ketty controller's routes, you will need to reach this endpoint:
<your-api-host>/ninja/cats/ketty


Update This approach is outdated today if you using NestJs v8.0.0 or later, as the documentation of nest-router tells us it's now included on @nestjs/core

and also as pointed by @yehonatan yehezkel, you can follow the documentation for the recommended approach at here https://docs.nestjs.com/recipes/router-module

3 Comments

I think this do not answer this requirement "I also need the :account parameter to be accessible from all the children routes.".
Check out the part about nested route: github.com/nestjsx/nest-router#params-in-nested-routes
this way is not recommended by nestjs docs because it became to complex to mantain docs.nestjs.com/recipes/router-module
16

Parent controller :

@Controller('accounts')
export class AccountsController {
  // http://api.domaine.com/accounts
  @Get()

Child controller :

@Controller('accounts/:id')
export class ResourcesController {
  // http://api.domaine.com/accounts/1/resources
  @Get('resources')

5 Comments

...and then how you get :id from that second example?
method(@param('id') id)
This is the pattern I'm using, and it's the best I've seen, but it's still not great for an enterprise API. If you then want to have /resources/:id, you need to define another ResourcesController, perhaps renaming the one above to AccountsResourcesController to make 'space'. I wish there were a mechanism to annotate a class method to ignore the parent controller route / override it. If anyone spots this and finds a better way, please let me know!
@mikey I think use router module might work docs.nestjs.com/recipes/router-module
I have been wondering about the case, where :id for the accounts is not required. e.g. there is a relationship between accounts and resources but I want to get all resources. I would like to have a route: /accounts/resources but it appears that NestJS routes this to /accounts/:id instead.
6

you can simply do this

@Controller('trainer/:trainerId/heroes')
 export class HeroesController {
    constructor(private readonly heroesService: HeroesService) {}

    @Get(':id')
    findOne(@Param('trainerId') trainerId:string,@Param('id') id: string) {
       return `This action returns a #${id} hero trainer id ${trainerId}`;
    }

 }

the uri is:

http://localhost:3000/trainer/4/heroes/5

thr result is

This action returns a #5 hero trainer id 4

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.