I'm trying to convert a legacy PHP app to use the middleware paradigm, similar to connect/express.js.
I've started porting the code into separate middlewares so that every feature is neatly self contained and can be easily add/removed/re-arranged as needed going forward.
However, I'm finding that many of these middlewares depend on other middlewares. For example, I have a DebugBar middleware which adds a bar at the bottom of every page if you're either on dev (which is determined via an environment middleware), or if you're a super user (determined by auth middleware).
Our site also has a link menu which changes based on your user permissions. Your user permissions can't be determined until you're authenticated, and I don't want to authentic at all unless you're on a page that requires it (basically anything except the login/logout page and 1 or 2 other pages) — so there's also conditional middleware based on what page you're viewing.
Up until now I've been more or less copying how express does things, but as far as I can tell, they don't really have any examples of middleware depending on each other, and if they do, you would just monkey-patch the response object and subsequent middlewares would either depend on it or crash, which doesn't seem like a great way of doing things.
Questions:
- What's the best way to share data between middlewares? Monkey-patching a response object seems very fragile.
- How can I make it clear which middleware depends on what? There are a number of devs here, they can't all know the exact order that the app.uses must happen in.
Best Answer
(Disclaimer: I don't know any of the technologies mentioned in the question; I'm just inferring from the descriptions on the question itself and the linked articles.)
Dependency and the order of execution. Based on the linked documentation,
app.use(...)
in a particular order.There are some relevant design patterns and techniques that will help you maintain the correct dependency and order of execution.
Regarding "monkey-patch(ing) the response object",
To resolve circular dependencies between middleware, one can implement a middleware that would be executed at the very beginning. This middleware can do a "requirements gathering" on the request, to decide what other middleware will be potentially activated, and then set various flags on the request object.
This "requirements gathering" middleware should avoid doing the actual work that causes the circular dependency.
The authentication issue is not unique to any paradigm. It is a general user interface design issue that affects every application where the user doesn't need to authenticate up-front.
The core issue is this. After the user navigated to a page, and that page contains elements that will potentially require authentication, the questions are: