9

Is there a nice-looking way to create overloaded routes in NestJS application? I have some thoughts, but maybe I'm inventing a wheel. I couldn't find any ready approach though...

What I'm talking about is something like this (lets take https://github.com/nestjs/nest/blob/master/sample/01-cats-app/src/cats/cats.controller.ts as start point):

@Get()
async findAll(): Promise<Cat[]> {
  return this.catsService.findAll();
}

@Get()
@Roles('admin')
async findAllAdmin(): Promise<Cat[]> {
  return this.catsService.findAllAdmin();
}

In other words, I want have two routes with same URL, but distinguished by some other values (like role here).

My idea was to create my own decorator, instead of Get, which will fill some weight map, assign to each overloaded method unique path. And then, add middleware, which will get parameters from request, compare them against map, and do internal redirect (with next('route') or req.app.handle(req, res)) to appropriate new path.

But in that approach I couldn't get user from request, if they should be authenticated with AuthGuard on one of methods...

yumaa
  • 965
  • 9
  • 18
  • 2
    Seems like a lot of overhead when you could just have a simple `if` branch in your controller that calls different service methods – Jesse Carter Feb 11 '19 at 21:28
  • Maybe, but I expect many such methods, and `if` branch in each of them looks like a lot of boilerplate to me... Also, methods could have different parameters, for example, imagine `@UserAccount() account: Account` parameter decorator, which will inject user's account in user-related method, but could fail on system admin role, in admin-related method. – yumaa Feb 11 '19 at 21:52
  • Oh, and I forgot main reason, why I cannot do it as single method! In my case, User and Admin authenticates in a different way — users uses usual sessions, while admins are used for external API usage, and authenticates with bearer tokens. – yumaa Feb 11 '19 at 21:57
  • (Joining the party late) - If it's all so different cases - why does it have to be the same endpoint at all? why not add another controller with an `'admin'` prefix? – ZimGil Aug 14 '22 at 13:22
  • Wow, resurrected after 2 and half years :) As far as I remember, I've implemented what I wanted (custom decorators with roles weight map), but finally replaced it with different endpoints, yes, in sake of mental overhead and future support. – yumaa Aug 15 '22 at 05:54

1 Answers1

0

It is not nice looking but let's give it a try.

  1. Create a custom decorator
import { createParamDecorator, ExecutionContext } from "@nestjs/common";

export const IsAdmin = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    // Here add the logic to know if is an admin from the request
    return request.role === "admin";
  }
);
  1. Update your controller
@Get()
async findAll(@IsAdmin() isAdmin: boolean): Promise<Cat[]> {
  if (isAdmin) {
    return this.catsService.findAllAdmin();
  }

  return this.catsService.findAll();
}