I have some express routers specified like so:
const getFooRouter = Router().get('/foo', (_, res) => {
res.json({ method: 'get', path: 'foo' })
})
const putFooRouter = Router().put('/foo', (_, res) => {
res.json({ method: 'put', path: 'foo' })
})
const postBarRouter = Router().post('/bar', (_, res) => {
res.json({ method: 'post', path: 'bar' })
})
Then I compose these into a single router representing the whole app logic
const mainRouter = Router().use(getFooRouter, putFooRouter, postBarRouter)
Finally I create an app, and run it like this:
const expressApp = express()
expressApp.use(mainRouter)
expressApp.listen(3333)
What I'm trying to do next, is add another Router
that looks like this, to handle CORS, specific for each path:
const corsRouter = Router()
.options('/foo', (_, res) => {
res.json({ method: 'options', path: 'foo' })
})
.options('/bar', (_, res) => {
res.json({ method: 'options', path: 'bar' })
})
Then add this after my main router, so my app looks like this:
const expressApp = express()
expressApp.use(mainRouter)
expressApp.use(corsRouter)
expressApp.listen(3333)
The issue is, that none of the handlers get hit in my CORS router. Instead, when I hit for example OPTIONS http://localhost:3333/foo
I'm getting something, what I assume express is doing on its own, which is a peculiar response with this body:
GET,HEAD
If I remove mainRouter
, and my setup looks like this:
const expressApp = express()
expressApp.use(corsRouter)
expressApp.listen(3333)
The requests are going through fine to corsRouter
. I'm using Insomnia for testing if it matter.
Question: What am I doing wrong in terms of structuring these routers?
NOTE:
- Pease don't suggest ready-made CORS middlewares or similar stuff like that, I'm specifically interested why my
corsRouter
is not getting hit in this setup, and what do I need to do to correct this. - The reason it's structured like this, because this is generated from an OpenAPI document, and the structure lends itself nicely.
CodePudding user response:
It looks like a router instance, when hit with an OPTIONS
request, will, if none of its routes matches the request but it has routes for other methods that match the same path, run a default OPTIONS
handler which returns the response you see (GET,HEAD
).
In your case the mainRouter
is receiving requests first and it will run the aforementioned default handler.
If you switch around the order in which you mount the routers, it works as expected:
expressApp.use(corsRouter)
expressApp.use(mainRouter)
You can philosophise about whether this is a bug or not. My guess is that due to Express internals, it can't keep track if a (sub-)router has handled the OPTIONS
response, so it will basically get default-handled by the first router that "finishes".
An alternative way of fixing this is to declare the OPTIONS
handler on the router that handles the "regular" request.