Skip to content

[fix] Very odd behavior with router.param() handlers #194

@joekrill

Description

@joekrill

Describe the bug

Node.js version: 22.8.0

OS version:

Description: router.param() handlers are not called consistently, may be called multiples times, or not called at all, depending on the order they were created (and in particular, the order in relation to other verb handlers).

Actual behavior

When param() handlers are defined, whether they get called, how many times they get called, and in what order depends entirely on when the related verb was registered. This mostly happens when using multiple param() handlers for the same parameter. But there are also issues with just a single param() handler being called multiple times in some cases (see the last test in the example repo for a case of this happening).

For example, given the following router:

const router = new Router();
router
  .param('id', (id, ctx, next) => {
    console.log("param handler 1");
    return next();
  })
  .param('id', (id, ctx, next) => {
    console.log("param handler 2");
    return next();
  })
  .param('id', (id, ctx, next) => {
    console.log("param handler 3");
    return next();
  })
  .get('/:id', (ctx) => {
    console.log("get handler");
    ctx.status = 200;
  });

a GET /:id request will ONLY call the last param handler. The first 2 handlers are ignored completely.

Then there's this scenario where, if you have multiple matching verb handlers, some of the param handlers can get called multiple times:

router
  .param('id', (id, ctx, next) => {
    console.log("param handler 1");
    return next();
  })
  .get('/:id', (ctx, next) => {
    console.log("get handler 1");
    return next();
  })
  .param('id', (id, ctx, next) => {
    console.log("param handler 2");
    return next();
  })
  .param('id', (id, ctx, next) => {
    console.log("param handler 3");
    return next();
  })
  .get('/:id', (ctx) => {
    console.log("get handler 2");
    ctx.status = 200;
  });

In this case a GET /:id request will result in:

  • param handler 1
  • param handler 2
  • param handler 3
  • get handler 1
  • param handler 2
  • param handler 3
  • get handler 2

so param handlers 2 and 3 get called twice.

Expected behavior

All param() handlers should be called once, in order, for any verb that uses that parameter, regardless of what order they were registered in. Or

-- or --

The documentation should be updated to make it clear that only a single param() handler per param name is supported. But there is still a bug where a param() handler can get called more than once, like here:

 router
  .use('/:id', (ctx, next) => {
    console.log(use1');
    next();
  })
  .param('id', (id, ctx, next) => {
    // This gets called twice for a `GET /:id` request
    console.log('param1');
    next();
  })
  .get('/:id', (ctx) => {
    console.log('get1');
    ctx.status = 200;
  });

Code to reproduce

Tests added to this branch showing the bug:

https://github.com/joekrill/router/tree/params-bug

npm run test:params

Checklist

  • I have searched through GitHub issues for similar issues.
  • I have completely read through the README and documentation.
  • I have tested my code with the latest version of Node.js and this package and confirmed it is still not working.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions