I am writing a REST API using express. There are multiple endpoints and each has its own specific router. While each endpoint does specific tasks, there are some operations that are common among all requests like auth, logging, and formatting the result into a common output. These tasks are all performed by middleware on the base router, some before the endpoint router and some after.
//v1Router.js
...
//auth, set common headers, etc
app.use(preHandler)
//route to endpoints
app.use('/endpoint1', endpointRouter1)
app.use('/endpoint2', endpointRouter2)
app.use('/endpoint3', endpointRouter3)
//format and send data
app.use(postHandler)
//catch any errors from the chain
app.use(errorHandler)
//endpointRouter1.js
...
router.get('/people', getPeople)
router.get('/people/:id', getPerson)
router.get('*', handleBadPath)
function getPeople(req, res, next) {
res.locals.data = /*some data we got from db*/
next()
}
...
I have implemented this such that all functions of the endpoints are middleware, and data within these endpoints (for example content retrieved from the database) is saved in res.locals
as it is in an intermediate state. Then the last piece of middleware before error catching on the base router level (postHandler
) formats the contents of res.locals
into the documented output, logs overall request-handling stats, and sends it to the user with res.json()
.
This is causing a problem for me because now I am finding it hard/impossible to use "catch-all" handlers for unsupported routes within the specific endpoints. The above example doesn't work because in endpointRouter1
, every request would make it to the catch-all. Each handler above the catch-all does not send the result and end the flow, but instead saves to res.locals
and calls next()
.
With this in mind I'm wondering if there is a best practice for when I should be calling res.json()
? Have I implemented a bad approach? Some alternatives I've thought of:
- Have the results sent from within each endpoint, with each route handler calling a common function to package and send the data.
- Have the results sent from within each endpoint, and have the
postHandler
function bound to the response like in this answer
However If my current approach is reasonable for the flow of data through the routers, how can I properly implement a catch-all for improper requests?