Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow middleware to be executed even when no route was matched #239

Closed
per2plex opened this issue Feb 10, 2016 · 2 comments
Closed

Allow middleware to be executed even when no route was matched #239

per2plex opened this issue Feb 10, 2016 · 2 comments

Comments

@per2plex
Copy link

I just started using koa@2.x together with koa-router@7.x and noticed that middlewares don't get executed if no defined route matches, coming from express this was kinda unexepected. I searched if this was by design because even examples in the README don't seem to expect this kind of behavior, e.g:

https://github.com/alexmingoia/koa-router#nested-routers (posts.allowedMethods() middleware will never be called, because no route matches the other HTTP methods)

I found the following issue: #182
which was fixed by: e486a93

The comment made just some days ago by @rockie suggest that i'm not alone with this issue and that this problem also exists in the 5.x version of koa-router.

If I remove the route check for my project, everything works as expected.

Take the following code as example, I want the API to respond with JSON for all errors allowedMethods throws on the /api route and to respond with HTML for everything else:

const Koa = require('koa')
const Router = require('koa-router')

const app = new Koa()
const router = new Router()

const apiRouter = new Router()

apiRouter.use((ctx, next) => {
  return next().catch(err => {
    ctx.status = 405
    ctx.body = { error: err }
  })
})

apiRouter.get('/entity', (ctx) => {
  ctx.body = { id: 0 }
})

router.use('/api', apiRouter.routes(), apiRouter.allowedMethods({
  throw: true
}))

router.get('/', (ctx) => {
  ctx.body = 'HTML'
})

app.use(router.allowedMethods())
app.use(router.routes())

app.listen(3000)

I expect POST /api/entity to return a JSON response:

{
    "error": "Method Not Allowed"
}

but the middleware will be ignored completely and the top level allowedMethods will handle it and return HTML:

Method Not Allowed

This example also works as expected if the route check is removed.


I can think of many more use cases where middleware without matching routes are required. So is this behaviour really by design or am I doing something completely wrong?

@alexmingoia
Copy link
Collaborator

The whole point of route-specific middleware is to run middleware for a specific route. Otherwise there would be no difference between app.use() and router.use(). If you want middleware to run regardless of any route matching you can mount it on the app via app.use().

Instead of nesting the apiRouter as route middleware for router, mount apiRouter separately using app.use('/api', apiRouter.routes(), apiRouter.allowedMethods())

@per2plex
Copy link
Author

@aheckmann Yeah, you're right. I gave it some more thought after I wrote this issue and it's actually more logical that way and the example above is actually the only use case where it would profit from working the other way, but there are some other clean solutions for that problem.

I'll close this issue. Thanks for the quick response tho, nice project you got here 👍

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

No branches or pull requests

2 participants