Stuck in the middle

Shahaf Mezin
4 min readMay 16, 2022

--

What is Middleware?

To understand middleware we first have to understand the flow of our request pipeline, from when it leaves the client, and till the response comes back to the client.

Of course we know that the SERVER is in charge of parsing the request and providing the response, but what if we want to prevent certain requests from ever getting into our controllers? or what if we want to manipulate the request or response before we handle it?

The good news is that we can do all that, and even enhancing performance while doing so, by using middleware. Middleware is a software component that hooks into the request pipeline to handle web requests and generate responses. Each middleware can process manipulate the request as it is received from the previous middleware on the way to the controller, on the response on the way back from the controller to the client. Each middleware can also ‘Short circuit’ the flow and return back the response before the request ever reaches the controller. Lets look at a simple visualization:

simple middleware design

How it works

Every request sent by the client first goes through the middleware in the described order (log->auth->cache)

The image above shows us how the Request pipeline combined with Middleware that handles logging, authorizing and caching. Each component can manipulate the request, for example, the auth middleware can generate jwt token and add it to the AUTHORIZATION request header, if credentials are good, and deny access otherwise. In the later case, where credentials are invalid, the middleware will ‘short circuit’ the flow and return the response before the request even gets to the app (or to the ‘cache’ middleware). This behavior carries advantages both in performance and security aspects.

Use cases for using middleware

One of the first things to consider if something you want do to should be a middleware. So middleware is best for cross cutting concerns. If it is a specific business logic, only applies to very few cases then, perhaps middleware isn’t the way to go. If your app have many common tasks (such as logging, authentication, parsing JSON or add some common share data to every request or response), then refactoring out that logic into middleware makes sense. lets look at a couple of examples:

Logging

Assuming we want a record of each request and response metadata, putting our logging mechanism in a middleware will be a good idea. That is a simple task, common for every request and response, and a task that has nothing to do with our app business logic.

Error handling

Much like the logging task, a global error handler also should provide service for every request and response our app handles, and it also presents a simple common mechanism that makes it a good middleware candidate.

Ordering

Each middleware is instantiated as one block in our request-response pipeline, thus ordering is crucial for functional correctness. However, even if two middleware can be re-ordered, you should think about the performance or security implications. Lightweight middleware that have a short circuited return path should go before heavier middleware.

As an example, middleware that redirects non-HTTPS to HTTP domain via a 301 Permanent Redirect should be placed before middleware that decompresses and parses the request body. Otherwise, you’re wasting CPU cycles decompressing a body that will be thrown away.

Think about security and DDoS protection also. If only a specific whitelist of IP addresses are allowed to access your API, and all others are denied, you probably want to check the IP address before performing expensive operations such as querying account information in a database.

Advantages

Using middleware carries numerous advantages and hardly any disadvantages, lets take a look at the main ones:

Security. ‘Unwanted’ request without bothering the endpoint — requests that do not follow our desired policies or have the necessary permission will be rejected before the action.

Responsibility. One of the most important OOD design principles is keeping Single Responsibility for every component, and not repeating ourselves. Wise usage of middleware will ensure consistent, app wide, treatment to every request, while each middleware performs it’s one single task, such as parsing, logging, authorizing etc.

Performance. Filtering out requests before it reaches the action can save latency and code repetitions.

Summary

The Middleware is software code, which processes the incoming requests and outgoing responses. Using it wisely will make your code safer, faster, and easier to read and maintain. Since every major framework supports middleware (sometimes called ‘filters’ or ‘delegation handler’) it would be a bad practice not to utilize its advantages. It’s few (arguable) disadvantages are regarding business aspects of developing time, not something that should bother you on your way to excellence :)

--

--