Laravel: Making middleware understandable
One of the magic around Laravel middleware is how you declare them in your routes: using just a simple string. To quote an example, the request throttler is called
throttle, and you can set it in one line along some parameters.
This is not magic. The middleware name is aliased in the HTTP Kernel of your application, which avoids you using the full middleware namespace.
The case of large middleware declarations
The point of middleware is how simple they’re to declare. Most of the time you’re a string away, but you may have a package that inevitability demands you to set a large set of parameters.
For example, my Captchavel package contains a middleware that, depending on the application, can require around three to four parameters.
The latest PR I made wanted to simplify this using a small idea: what about declaring a
Stringable object? Once the objects goes into the
middleware method, it transforms into a string and walá. Well, that’s now possible.
We can use a fluid setter that will translate a bunch of what-does-what strings into something with lower cognitive load to understand.
The direct benefits are not in the framework, since the only middleware that requires more than one parameter is
throttle, and that one is used rarely.
Rather, the huge amount of packages that must deal with middleware will benefit from this. By using a
Stringable object we can:
- avoid using the middleware by the class name if it’s not aliased, and
- set parameters in any order.
While the declaration becomes larger by a few characters, the intention is clearer, which is a huge win in terms of maintainability.
Behind the scenes, any class object implementing the
Stringable interface will do the heavy lifting on the
__toString() method. For example, this is a simplified example of how the
ReCaptcha class helper works:
There are a myriad of advantages of using objects that can be represented as strings. To summarize:
- Lower cognitive load to understand what value does what.
- It’s no longer obligatory to register an alias into the HTTP Kernel.
- It’s no longer required to push a middleware class names and concatenate parameters manually.
- You can set values in any order.
- You can set a defaults values in the helper instead of the middleware itself.
The one caveat of declaring middlewares is the nature of the parameters. All parameters that are passed to the middleware will become strings. You will have to cast them into their appropriate type inside your middleware, like in the case of integers, decimals and lists.
Since all parameters are strings, the last member of the string
foo, will transform into an empty string, not in
null, so you may need to act accordingly in your middleware.
Overall, it’s a nice addition to the framework. It could have been simpler if we could have used union types for the argument, transform the string into an array, and cast to an string each member, but that would have been catastrophic as it would have broken the app for anybody below PHP 8.
I hope this little feature helps when dealing with middleware that quickly becomes a one line scrawl.