How best to route dynamic and static routes in Express - node.js

I have a small-ish project I'm working on and I want to be able to have routes like this work at the same time.
indexRouter.get('/section/:path*', sectionController.pathLogic);
indexRouter.get('/section/about', staticController.about);
Currently, the * in /section/:path* catches everything and /section/about is ignored.
Is there a way to handle both of these routes at the same time?

The order that you define the routes matters, so always put general routes last when you define them. The router traverses down through the tree of routes and if it finds the possible route it stops there (unless it's middleware and calls next()). So in your case, the route with '*' is more general, so the router stops there.

Related

Minimizing duplicate routes index.js

I am trying to build a REST API with express router, which contains of nested sub routes. I have mounted these sub routes in my index.js file.
I have defined it as follows:
// Mounted routes
app.use('/api/v1/Project', new ProjectRouter().routes);
app.use('/api/v1/Project/:projectId/Context', new ContextRouter().routes);
app.use('/api/v1/Project/:projectId/Context/:contextId/Question', new QuestionRouter().routes);
app.use('/api/v1/Project/:projectId/Context/:contextId/Question/:questionId/Answer', new AnswerRouter().routes);
I want to arrange my routes revolved around the functionality and being more complaint towards REST standards.
In the above case the route prefix /api/v1/Project/ is being
repeated over and over again.
Is there some best practice to minimize the redundant routes by
prefixing?
I solved my problem by using the approach detailed in this link Nested Router in Express.JS.
The solution being we have to just mount the nested router in the module as follows:
app.use('/:nestedId/nestedRoute', nestedRouter);
Furthermore we need to also merge the parent route parameters also, we can do this by passing the options object to the express.Router method:
const router = express.Router({ mergeParams: true });

How to prevent express server from serving api routes from the static folder

Hi I need some help with how express handles routes.
In setting up my express app, I have something like this:
app.use(express.static('public'));
Next, I mount some api routes:
app.use('/api', myrouter);
app.get('*', function(req, res) {
res.sendFile(path.resolve('public/index.html'));
});
But, when the frontend requests data via an api route, e.g. at 'localhost:3000/api/things', I am seeing in the Express debug logs that at some point (unsure when) it actually tries to serve this request as a static file, like:
send stat "C:\myproject\public\api\things" +230ms
Even though this folder doesn't exist in 'public' and should be solely handled by my api. FYI, the handler for /api/things route is only implemented for the GET method, and does get invoked at some point.
How do I stop express server from also trying to serve api requests from the static folder?
Thanks very much.
Answering my own question... which appears to be a duplicate of this one:
`express.static()` keeps routing my files from the route
So the answer is this one: https://stackoverflow.com/a/28143812/8670745
In short, the app.use() declarations that mount your api routers should appear before the app.use() statements which tell express.static where to serve your static files from. This way, the latter acts as a catchall AFTER api route handling is done. Router engine order matters...
Your answer is misinformed, or rather you've misinterpreted the problem. Your original configuration:
app.use(express.static(__dirname + 'public'));
app.use('/api', myrouter);
Looks absolutely fine because there's no clash between the routes. The threads you've linked too aren't really the same, and I can see why moving the routes in those cases would have worked.
The only thing I'd say is your path to your static folder isn't reliable, you should really use path.join, or actually in your case you can just do express.static('public') - express will infer the folder your app is served from.

When to use controllers?

This is what I'm doing right now:
Implemented different router modules for different routes
Each router has it's own sets of MongooseModels.
Handler the request (req,res) and interact with the MongooseModel via statics and methods
This is what I want to know:
Almost every example is see where Mongoose,Express are involved, they seem to follow the MVC pattern, which places "Controllers" in between. Now, I have statics and methods defined in each MongooseModel and are capable of handling only the (req.body) part of my original (req) (Because, that's what they only need, right?). Extract the result, and the rest is done by the router.
So, do I really need to place Controllers in between as my MongooseModel is already doing the same job?
Thanks.

How can I inspect the set of Express.js middleware that is being used?

Backstory: I'm trying to debug an issue in one piece of middleware that I think is coming from other piece. But, I'm not sure. So anyway, I would like to be able to check what middleware is actually being called, because I'm not sure of the ordering.
Is it possible to inspect the set of middleware that is currently being used?
I have tried to find any piece of internal state where Express might be storing the middleware, but I was not able to.
You can't see what is specifically "middleware", but you can inspect all registered handlers.
In express 4:
// Routes registered on app object
app._router.stack
// Routes registered on a router object
router.stack
Fine for inspection/debugging, probably not a great idea to program against any variable prefaced with an underscore.
How middleware works:
The middlewares are generally used to transform a request or response object, before it reaches to other middlewares.
If you are concerned with the order in which the middlewares are called, express calls the middleware, in the order in which they are defined.
Example,
app.use(compression());
app.use(passport.initialize());
app.use(bodyParser());
app.use(cookieParser());
the order is
compression,
passport,
bodyParser,
cookieParser
(plus I think your bodyParser and cookieParser middlewares should be before the other middlewares like passport).
That is the reason why the error handling middlewares are kept at last, so that if it reaches them, they give an error response.
So basically, request drips down the middlewares until one of them says that it does not want it to go any further(get, post methods are such middlewares, that stop the request).
Now, the debugging part:
You may not be able to inspect the middleware properly internally, but you can check whether middleware has worked properly by inserting your own custom middleware in between and then put a breakpoint on it.
Let's say you want is to debug what happened to your request after the bodyParser middlewares does it tasks, you can do is put your custom middleware in between and check the request and response whether they are modified properly or not.
how you do this is by following example.
Example,
app.use(bodyParser());
//custom middleware to inspect which middleware is not working properly
app.use(function(req,res,next){
console.log("check something!"); //do something here/put a breakpoint
next();
/*this function is the third parameter
and need to be called by the middleware
to proceed the request to the next middleware,
if your don't write this line, your reqest will just stop here.
app.get/app.post like methods does not call next*/
});
app.use(cookieParser());
This is one way in which you move this custom debugger in between the middlewares, until you figure out which one is giving faulty outputs.
Also, if you want to check the middlewares functionality, you can look at the documentation of those middlewares. They are quite good.
Check by playing with your custom middleware.

Express router conflicting with Backbone pushstate

An Express / route serves my Backbone's app index.html.
I'm using pushstate in Backbone but the routes that Backbone should handled are being handled by express, giving 404 responses.
How can I setup Express to serve the index.html but to delegate other routes to Backbone?
In this situation you have multiple options:
You can have a server that handles the same routes as the client does and returns the same results. It is hard to implement but it gives a good url. Github did this.
Always return index.html and handle the route client side. (That is somewhat ugly and hard to maintain)
Don't use pushstate. Amen.
You can use /* approach. Just have it as the last route. That way the other routes such as any service API calls will be matched before the catch all route of /* is matched. This is also how Backbone handles its routes.

Resources