Express middleware and parameter handling ordering on route - node.js

So I am running some API tests and I noticed that one test is failing because it is running some parameter handling logic before middleware, now here is an example of the route definition:
app.post("/something/:some_param",
middlewareA, middlewareB, middlewareC,
function(req, res) {
// Do stuff
});
Now I assumed (wrongly I think) that middleware would be invoked first then it would handle the parameter handler for :some_param however it seems to be the other way around. (by parameter handler I mean app.param())
Problem I have here is that if the above is correct and parameter handlers are run first, some of the logic within the parameter handler assumes the user is logged in already and blows up if they are not, and middlewareA handles user authentication and if they are not logged in redirects them etc, so ideally I would want middlewareA to be called first, so is there a way to achieve this ordering?
The only way I could see this working would be if the parameter handler could utilize middleware but there is no documentation on the API docs on this subject, so is there any best practice to handle this sort of scenario? as I do not want to have to shoe horn my middlewareA logic into my :some-param handling logic as I also have many other :other-param handlers etc which would also need this authentication (and other) middleware run before they run.

Yes, param handlers run before middleware. You can deal with this by either:
recoding your param handler as a middleware. There's not that much difference between the 2 mechanisms.
OR, in your param handler, just run the desired middleware directly as below:
.
function someParam(req, res, next, paramValue) {
myAuthMiddleware(req, res, function (error, result) {
if (error) {
next(error);
return;
}
//Here the user will be logged in
// do what you need to do with req and paramValue
next();
});
}

Related

Calling `next()` in a route handler

Is it valid to call next() in route handler?
In my app I have a middleware at the end of the stack to handle all the unidentified requests.
What I want to do is to send an error page as response when the invalid title is encountered.
The snippet in question is the following:
app.get('/:title', (req, res, next) => {
const title = req.params.title;
if (title.isValid()) {
res.render('post', { title });
} else {
next();
}
});
This is the middleware to handle the unidentified requests:
app.use((req, res, next) => {
res.status(404).render('error');
next();
});
FYI: the snippets above do work. I am just not sure if this is the right way to implement this sort of behavior.
You have basically three choices when you want to send an error response.
You can just send the error response right where the error occurs and not call next().
You can call next(err) where you create an appropriate Error object and let Express' error handling process that error and send the response (which could also be your own custom error handler that the error would flow to).
You can call next() and rely on hitting your default 404 error handler (as you show in your question). This will only work if there are no other routes that might also try to handle this request.
There are logical reasons for any of these methods, depending upon your app architecture plan and just how you want to do things. All can work.
Is it valid to call next() in route handler?
Yes, if you want to continue routing to other route handlers or you know there are no more route handlers that will match and you want it to flow to the 404 error handler.
You can use next() equally well from either middleware or a route handler. It behaves no different in either. The main difference between app.use() and app.get() is just in how it matches the route, not in what happens once the middleware/route handler executes on a matching route. They work the same in that regard.
FYI, app.get() is JUST a more specific version of app.use().
app.get() only matches the GET http verb whereas app.use() matches all http verbs.
app.get() requires a full path match, app.use() will match on a partial path match. For example the path /category/mountain will match app.use("/category", ...), but not app.get("/category", ...).
See What is the difference between a route handler and middleware function in ExpressJS? for some further explanation.
Once they've matched are are executing the code in the handler, they work identically with next() or res.send(), etc...
So, it's perfectly fine to use next() in a route handler if your desired architecture wants to do it that way. You do have to make sure you're always sending exactly one http response for an incoming request. Never failing to send a response and never sending more than one response. So, that becomes a requirement of however you choose to do things. For example, you would never call next() AND send a response in that same handler because that would likely lead to sending multiple responses.
There are even cases where you might have two matching routes for the same path and if the first one decides that it shouldn't handle the request (perhaps because of some state or some query parameter or something like that), it can call next() to allow the second one to get a chance to process that request.

Whats the difference between a Controller and a Middleware

I am writing and API in express.js. the original API I wrote only utilized routes and raw SQL queries. I have since rewritten the API for the most part NOW using an ORM to react models and migrations.
My question what is the difference and use cases for middleware and controllers. currently only using middleware because most sources online online only explain what a middleware is.
I don't understand the use case of a controller. and I don't want to omit it from my API if its used in proper programming conventions
You should see middleware as a step in your API and controllers as the entity that will actually respond to the requests.
Bellow is an example where authenticationMiddleware is a middleware because it is a step during the processing but should not return the response. It can though, in case of error.
Then getItems actually handle the logic specific to this calls.
As a rule of thumb, middleware are often reused more than once and often they do not response. On contrary, controller respond and are most of the time specific to one endpoint.
const express = require("express");
const app = express();
function authenticationMiddleware(req, res, next) {
// Check that the user is authenticated using req.headers.Authorization
// for example
if (authenticated) {
// The user is authenticated, we can go to the next step
next();
} else {
// The user is not authenticated, we stop here
res.status(401);
res.send("Error during authentication");
}
}
function getItems(req, res, next) {
// Here we focus on the actual response, we assume that the user is authenticated
res.send({ items: [] });
}
app.get("/items", authenticationMiddleware, getItems);
app.post("/items", authenticationMiddleware, createItems); // Re-use the same middleware
app.listen(3000);
If you're referring to the node/express terminology, middleware are simply the callbacks used by the routing functions/methods (get, set, delete, use, etc). Callbacks can either send or not send responses back to the client. The callbacks are really the 'controllers' if you'd like to call them that (eg: ASP.NET Core MVC) but that's up to you. Below is a quote from Express. Note the term 'middleware' and where there's no mention of a 'controller'.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware
function in the application’s request-response cycle. The next
middleware function is commonly denoted by a variable named next.
Middleware functions can perform the following tasks:
Execute any code.
Make changes to the request and the response objects.
End the request-response cycle.
Call the next middleware function in the stack.
'Express' also defines different types of middleware which is useful:
Application-level middleware
Router-level middleware
Error-handling middleware
Built-in middleware Third-party middleware
Here's another nice look at it from Mozilla's pov that does mention a few controller/callback examples.
Beyond that, you can define what a 'controller' is within your team and the naming convention follows from there. Key is your SOLID profile and how you separate your concerns.

ExpressJS middleware vs logic

What is the best way to structure the logic in an ExpressJS API.
So lets say I want to create a register and login function, and lets say I want a user to be logged in when he is successfully registered.
Now there are different ways I can achieve this, my question is then essentially: Which method is best and why?
METHOD 1
Everything is middleware:
router.post('/path', someMiddleware, register, login, function(req, res){
//You are registered and logged in.
});
So here both the register and login is treated as middleware, with both of them ending with a call to next(). This also results in the best reusability, because I can call either login and/or register again in any other express routing.
METHOD 2
Register is middleware and calls login (which is now just a standard function):
router.post('/path', someMiddleware, register, function(req, res){
//You are registered and logged in.
});
So here register is still middleware, but just before calling next() it calls login() which in this case is not middleware. The problem here is that if user that is already registered wants to login, should I create a hybrid login function that is also middleware and just call it in that specific post request?
METHOD 3
Logic is not in middleware and gets called in the wrapper:
router.post('/path', someMiddleware, funcWrapper(register, login), function(req, res){
//You are registered and logged in.
});
and then (in pseudo):
funcWrapper(actions...){
foreach actions
action()
}
Here logic and middleware are split, there is a wrapper that loops through all the functions that are passed in as parameter (in this case register and login)
Just a last question:
If I haven't asked enough questions, I have a last one. Is it better practice to end all express routing calls with
..., function(req, res){
//response
});
or with
..., lastMiddleware);
and then in the lastMiddleware there is some response

Is it possible to use some sort of 'middleware' after sending the response with express?

The typical middleware in express is used before the request hits the routes, for example there's authentication first, then the code of the specific route is executed, then the response is sent.
I am wondering whether it is possible to have a thing like a middleware after a route is hit.
Say I have five routes that all respond with some json and I wanted to log the sent json everytime one of the routes is hit.
I could go and log manually everytime I send a response in a route, like this:
console.log(data);
res.json(data);
but this seems redundant to me. A better approach could be to wrap that in a function to call in the route, but that would require to pass the response object everytime like this:
/* instead of the above */
send(data, res);
/* and then somewhere else usable for all routes */
function send(data, res) {
console.log(data);
res.json(data);
}
this also seems a bit like bad practice to me, so I'm wondering whether this would be the preferred way or if there's a way to use some kind of 'middleware', which would allow to send the response in the usual way and hook in after that.
It is not really possible to attach a middleware which executes after the route, but you can execute a middleware, which binds a finish event on response,
app.use(function(req, res, next){
res.on('finish', function(){
// Do whatever you want this will execute when response is finished
});
next();
});
also https://stackoverflow.com/a/21858212/3556874

Authenticate before calling route controller

I'm working on an API using restify. There will be a dozen or more endpoints and each one requires authentication. The API will be stateless, so each API request, regardless of endpoint, will pass credentials.
What I'd like to do, if possible, is to authenticate before negotiating the route. Otherwise, if I have a route:
server.get('/activities', activities.index);
Then, within activities.index (and every other routing method), I have to duplicate the following:
var user = require('../models/user')(server);
user.authenticate(req.authorization, function(err, user) {
...
// Do the real activities-related stuff.
});
This is one of those things where it feels like there must be a better way of doing it, but I don't know what it is.
Anyone have any thoughts?
So you can register handlers to be ran before every route is ran.
http://mcavage.me/node-restify/#Common-handlers:-server.use()
server.use(function(req, res, next){
//do authentication here
if(authenticated){
return next();
}
else{
res.send({auth:false});
})
So when you use server.use when the user asks for /activites it will run all of the server.use you created in the order you created them before running the code for the route.

Resources