“Middleware” sounds fancy, but just means “things we always do first” or “things we always do before we wrap up”.
Thought of the analogy of immediately answering the phone every time it rings vs starting by checking the caller ID.
Checking the caller ID = middleware.
Based on the caller ID values, you’ll either answer the call or ignore it.
Middleware is just a checklist you always apply. The steps in your algorithm that never change:
In the context of a web api handling requests:
handler:
GET -> route "/hello" -> OK "Hello"
GET -> route "/goodbye" -> OK "Goodbye"
POST
-> route "/user"
-> mustBeLoggedIn UNAUTHORIZED
-> requiresRole "Admin"
// etc
Source: pipeline-oriented programming youtube video by Scott Wlaschin at NDC Porto 2023
- Argues that most programs can be designed as a pipeline (comprised of pipelines, comprised of pipelines, etc) and calls out that “middleware” can also be demystified as nothing more than a request-handling pipeline
- Calls out that you do not need the OOP interface/adapter patterns often used to model a domain and can often model and test the same domain more simply and clearly as workflows composed of function call chains with input/output types described in domain-specific language (e.g. outputting
AuthorizedUser
rather thandict
andValidatedEmail
rather thanstr
) - Loving his other talks too, which demonstrate this “Domain Modeling Made Functional” via leaning heavily on custom types (rather than primitive types like
str
,int
etc) that describe the domain, and pipeines (or “workflows”) that describe the business logic - Getting off topic here, but he also emphasizes that pushing IO to the front and end of each workflow/pipeline gives you an easily unit testable core of pure sync (not async) functions that comprise your domain logic