It is a great concept that you can implement middlewares in ExpressJS. A lot of frameworks have been using this idea, copied from ExpressJS, since. ExpressJS is basically a double pass middleware. “Double pass middleware receives both the request and a response in addition to the handler, and passes both the request and response to the handler when invoking it”. Below is a normal implement of our ExpressJS function:
Triggering a middleware before the response is great. However, there are scenarios where you might want logging after response has been completed. You can achieve this in the responseHandler or by adding a afterMiddleware after our responseHandler in the ExpressJS route implementation. Lets look at the code below:
Trying to manipulate the response or headers in the afterMiddleware function will fetch us an application error — warning us that the response has been sent to the client.
However, there are a lot of scenarios where you might want to either manipulate the response after the responseHandler has been triggered, or you might want to perform other tasks after the response has been created. These may include advanced logging for analytics before response is sent, response validation, response sanitation, or just ACL based response manipulation.
It is important to note that when you use .send() function in ExpressJS, you cannot manipulate the headers nor the response. It is possible to do other activities (other than header or response manipulation) after the response is sent. This may be anything from logging, triggering schedulers, emailing, or some pub-sub action. However, again the headers nor the response can be manipulated since the response has been sent to the client already.
This creates a couple of use cases. May be once the response has been created, you might want to check if the response object variables or data to be sent is actually valid, authorised, and if not you may want to restrict it or remove that response data. Second, you may just want to log it off somewhere for analytics purposes, response sanitation, or just ACL based response manipulation, or just initiate a pub-sub application’s action after the response has been created/”supposedly” sent.
Lets create the code that will behave so. Instead of using the .send() we will create a .send() manipulator function called .response (function) attached to the ExpressJS response object that will allow us to trigger after middlewares (after responseHandler function trigger) in our ExpressJS application. Once all the after response middlewares have been triggered, we will use a final handler function that will take the pre-created response / after-middlewares-manipulated response and send it to the client. Lets look at the code below:
If you notice, the beforeAfterInjection function is the one that allows us to use a .response(obj) function. This is one of the most important functions and is always triggered first in the middleware list. The signification of the function is that it separates the logic of storing the response from the actual response handler function.
The next middleware in the implementation is the beforeMiddleware function which is a normal middleware that we have all been using before in ExpressJS.
Then comes a quite important middleware implementation where our application’s response handler resides. Notice that we have not used the responseHandler directly but we have actually wrapped this in a wrapper function that triggers the responseHandler function and then calls next() to pass the triggers to then next middleware — actually our after middlewares implementation — afterMiddleware. Do notice here that our implementation of afterMiddleware does not come at the cost of sending the response to the client. The response is yet stored in the request object as a req.res property rather than being sent to client. This afterMiddleware implementation allows us to do ACL checks, validation, sanitation, and all that you can think of in a cleaner and single-responsibility fashion from within the application. Instead of a single function taking care of all the work in the responseHandler, we are now delegating the tasks to other middlewares.
But, again, what happens if I use the .send() function instead of .response() function created by us to manipulate the framework for this kind of pattern? Well, actually, the response will be sent to the client even though the afterMiddleware is triggered. This can be nasty if you have business logic that needs the response to client to be held back for manipulation in the after middlewares. A .send() implementation instead of .response() implementation in this case results in an “application error” when trying to manipulate the response or headers; warning us that the response has been sent to the client. However, there may be cases where you might not need the response to the client to be held back; like say logging or sending a email trigger, etc. Such cases, you can actually use the .send() trigger of ExpressJS. The client will receive the response faster (rather on time) without having to worry about delays due to your application’s after response action’s logic. Lets have a look at such implementation below, again:
Now, you have a choice to for your implementation — using this application pattern or all other ways that you have implemented your business logic after the response has been created. However, testing can be a challenge like it is for your normal responseHandlers which needs a request, response, and next arguments to be passed while testing. You may be better off on performing API end tests in such cases, or segregating common logic from your middlewares to test. Choose one that you like, is more testable, or one that fits your needs more.
This application pattern of using middlewares both before and after helps you with better code segregation for responsibilities, response manipulation (removal of clutter in such cases), cleaner code, and more importantly allowing you to do something after the response has been created or sent; whatever, the scenario.
Let me know how I did, and if you learnt something new. Do leave your comments, and dont forget to like the article.