Skip to content

Fix: Ensure .use() middleware works when path or prefix contains parameters#203

Merged
titanism merged 2 commits intokoajs:masterfrom
MiccWan:fix/issue-202
Aug 28, 2025
Merged

Fix: Ensure .use() middleware works when path or prefix contains parameters#203
titanism merged 2 commits intokoajs:masterfrom
MiccWan:fix/issue-202

Conversation

@MiccWan
Copy link
Contributor

@MiccWan MiccWan commented Aug 19, 2025

Summary

Fix .use() middleware being skipped when prefix or .use() path contains parameters in @koa/router v14 (see #202 ).

Problem

  • In v14.0.0, @koa/router introduced a new option pathAsRegExp in Layer, which defaults to true for .use().
  • When pathAsRegExp is true, .use() paths are not processed with path-to-regexp; instead, they are passed directly to new RegExp().
  • As a result, if a .use() path or prefix contains parameters (e.g. /:id, /:version), the generated regex fails, and the .use() middleware is skipped entirely.

Minimal Reproduction

Example

import Router from '@koa/router';
import Koa from 'koa';

const app = new Koa();
const router1 = new Router();

router1
  .use('/:id', (ctx, next) => {
    // this will be skipped in @koa/router v14.0.0
    console.log('router1.use', ctx.params);
    return next();
  })
  .get('/:id', (ctx) => {
    console.log('router1.get', ctx.params);
    ctx.body = 'Hello World!\n';
  });

const router2 = new Router({ prefix: '/api/:version' });
router2
  .use((ctx, next) => {
    // this will be skipped in @koa/router v14.0.0
    console.log('router2.use', ctx.params);
    return next();
  })
  .get('/', (ctx) => {
    console.log('router2.get', ctx.params);
    ctx.body = 'Hello World!\n';
  });

app.use(router1.routes());
app.use(router2.routes());
app.listen(3000, async () => {
  await fetch('http://localhost:3000/123');
  await fetch('http://localhost:3000/api/123');
});

Steps to Reproduce

Run the script directly:

node index.js

Expected Behavior

Console should output:

router1.use { id: '123' }
router1.get { id: '123' }
router2.use { version: '123' }
router2.get { version: '123' }

Actual Behavior

Only the route handlers are triggered, .use() middlewares are skipped:

router1.get { id: '123' }
router2.get { version: '123' }

Changes

  • Updated .use() registration:
    • Replaced the match-all regexp ([^/]*) with an empty string "".
    • This still matches all paths but avoids breaking parameter handling caused by pathAsRegExp.
  • Removed redundant this.path empty string checks.
  • Tests:
    • Removed duplicate legacy tests.
    • Added new tests to cover the parameter-related .use() skipping issue.

Compatibility

  • No breaking changes expected.
  • All official usage patterns remain valid.

Checklist

  • I have ensured my pull request is not behind the main or master branch of the original repository.
  • I have rebased all commits where necessary so that reviewing this pull request can be done without having to merge it first.
  • I have written a commit message that passes commitlint linting.
  • I have ensured that my code changes pass linting tests.
  • I have ensured that my code changes pass unit tests.
  • I have described my pull request and the reasons for code changes along with context if necessary.

@titanism titanism merged commit 3ca5aa6 into koajs:master Aug 28, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants