The word Middleware is an ambiguous term that means different things to different people. We’ll try to find out what ‘Middleware’ means in commonly used frameworks and platforms for web development and how they are implemented.
- According to Wikipedia, middlewares are defined as: computer software that provides services to software applications beyond those available from the operating system.
- Enterprisy definitions for the word ‘Middleware’ are scattered across the web, each more vague than the previous.
- In most popular modern web development frameworks, a middleware is a hook into the HTTP request-response cycle allowing the execution of a common piece of code before/after a request is processed.
Do note that the code samples are intended only for implementation comparison in various languages. They may not be ideal for production use and may skirt some best practices.
Rack is a widely used interface between webservers and Ruby frameworks. A Rack middleware here is simply a piece of code that processes each and every incoming request before calling the next middleware in the rack to do its job. Once all middlewares are processed, the final response is returned to the webserver. In the case of multiple middlewares, they are processed in the order they are added to the rack.
Here is a sample Rack middleware that times the request:
So in this middleware, the start point is taken, then the actual call to the Server is made with
@app.call(env), then the logger outputs the logging entry and finally returns the response as
[@status, @headers, @body]
Django is one of the most popular Python frameworks for web development. As per Django’s official documentation: Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
Django allows you to define middlewares by duck-typing a class with specific well-documented methods. Here is a sample Django middleware class that times the request:
process_request() method is called for each request, before Django decides which view to execute.
On the other hand,
process_template_response() is called just after the view has finished executing, which prints the timer information.
Java EE Filters
Analogous functionality to Django and Rack middlewares is achieved through the use of Filters as specified in the Java Servlet 2.3 specification (2001).
Here is a sample
Filter implementation that times the request:
In this filter, the
chain.doFilter(request,response) calls the next filter in the chain and waits for it to be processed.
Once the request is processed, the response is generated and the filter returns.
Express is a web development framework for the Node.js platform. Middlewares in Express are similar to the Rack and Django middlewares in that you can hook into the request/response cycle.
In addition: it also supports application and router level separation of middlewares, which is not easily doable with Rack or Django. You can also mount middlewares onto specific routes, while ignoring other ones without having to write code manually for checking each route.
Here is a sample application level route for timing a request:
Here the call to
next() passes the control to the next middleware function in this stack.
The Java world is the only one that calls this function a ‘Filter’. This is probably because it was one of the first specs to come up with this kind of feature.
Interestingly, the Introductory blog for Rack (2007) by Christian Neukichen actually calls them filters, but also mentions the term middleware.
The origin of the term middleware in the context of the web seems to have come from the WSGI spec where it used for pieces of code that implement both ends of the API.
So now what?
Wanting to run common pieces of code before and after handling an HTTP request seems to be the most common definition for ‘Middleware’.
These naming inconsistencies resulted in some confusion for me, especially when switching between multiple languages. This blog post should serve as an online record of the naming problem.