Home > database >  Is there an easy way to keep query params on redirects in NestJS?
Is there an easy way to keep query params on redirects in NestJS?

Time:06-07

I am pretty new to this kind of stuff so any advice is appreciated, especially if there's a better way to solve this than what I am looking for.

I am trying to support an old endpoint by redirecting it to a new endpoint, and both endpoints should support query parameters. Each endpoint lives in a separate controller.

Example: I want /old-namespace/getStuff?foo=bar to redirect to /new-namespace/getStuff?foo=bar without manually rebuilding a query string like the Nest docs point out, because the params can be dynamic.

Looking at the NestJS docs, there is a handy @Redirect decorator that you can use on an endpoint like so, to easily redirect the request to a different URL:

@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
  if (version && version === '5') {
    return { url: 'https://docs.nestjs.com/v5/' };
  }
}

However, when using this, request.query is cleared on redirect (pretty sure this is expected behavior). Does anyone have a minimally-invasive solution for this? I've tested out building middleware/interceptors/custom decorators to get around this with varying degrees of success, but that seems heavy-handed and I wish there was a way to throw an extra param in the @Redirect decorator like retainQuery = true or something.

CodePudding user response:

I ended up using the top answer here: How to rewrite url path in Nestjs?

Ambroise Rabier's first response on nginx rewrites cued me in to search for a simple middleware solution since I didn't want to inject a service in multiple places, as there will be quite a few small redirects from old namespaces to new ones.

In a common module:

consumer
  .apply(RewriteApiEndpointMiddleware)
  .forRoutes('/')

In a middleware:

import { Injectable, NestMiddleware } from '@nestjs/common';

@Injectable()
export class RewriteApiEndpointMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    // the linked answer replaced "api" but in my case I needed to send "app" requests somewhere else
    req.url = req.url.replace(/^\/app/, '/new-namespace');
    next();
  }
}

CodePudding user response:

What you need is called rewrite in nginx.

I don't know if it work, but maybe you can do that ?

@Get('/old-namespace/getStuff')
getStuff(@Query() query) {
  // Done !
  getNewStuff(query);
}

@Get('/new-namespace/getStuff')
getNewStuff(@Query() query) {

}

If not, you can always do something like:

function handleGetNewStuff() {
}

@Get('/old-namespace/getStuff')
getStuff(@Query() query) {
  handleGetNewStuff(query);
}

@Get('/new-namespace/getStuff')
getNewStuff(@Query() query) {
  handleGetNewStuff(query);
}

However, if your issue is about changing the link on the user side (and not just for internal routing), you can try (not tested either):

@Get('/old-namespace/getStuff')
getStuff(@Req() request, @Res() response) {
  const newURL = req.originalUrl.replace('old', 'new');
  response.redirect(newURL);
}

Remember that NestJS use expressJS bellow.

  • Related