So now that we know what middleware is, let’s walk through how middleware is created.
Let’s create a middleware and then talk about each section of the middleware. We’ll keep this simple for now and just create a simple Hello World middleware and talk through it. Then we’ll get into the more complex middleware for our specific application.
This will create a HelloWorldMiddleware.py file for you inside the app/http/middleware directory.
There is nothing special about this directory, so you can move your middleware out of this directory if you like. Just make sure any imports in your config/middleware.py file point to the new location. This is more background information, so don’t feel like you need to move them though; this directory is fine.
Constructing Middleware
If we look at this class, you can tell that middleware is an extremely simple class with three parts. Let’s go through each part so we know what each is doing and what can be done with it.
It’s important to note as well that HTTP middleware and route middleware are constructed exactly the same. The only thing that makes it an HTTP or route middleware is how we register it with Masonite, which we will talk about in an upcoming section.
Initializer
The initializer is a simple __init__ method like any other class. The only thing special about it is that it is resolved by the container. So you can type hint application dependencies in your __init__ method, which will resolve classes much like your controller methods.
Since a lot of middleware requires the request class, Masonite will type hint the request class for you. If your specific middleware doesn’t need it, then you can remove it without issues.
The before Method
The before method is another simple method. Any code in this method will be responsible for running before the controller method is called. In the built-in auth middleware, this is what method is used to check if the user is authenticated and tells the request class to redirect back.
This method can also accept variables that we can pass in from our routes file. We will talk about this later on in the chapter.
The after Method
The after method is very similar to the before method except the code is ran after the controller method is called. This is where the logic would go if we wanted to minify the HTML response as an example.
This method can also accept variables that we can pass in from our routes file. We will talk about this later on in the chapter.
Registering Middleware
Now that we created our middleware class, we can register it with Masonite. We can import it into our config/middleware.py file and put it into one of two lists. We can put it in the HTTP_MIDDLEWARE list or the ROUTE_MIDDLEWARE dictionary.
HTTP Middleware
Remember earlier we said that both middleware are constructed the same, so if you want the middleware to run on every request, put it in the HTTP_MIDDLEWARE class .
Notice HTTP middleware is just a list, so you can just append it to the list. The order of your middleware may not matter, but it actually might.
The order the middleware is run is the same order you put it in the list. So the LoadUserMiddleware will run first and then the HelloWorldMiddleware will run last. Since our HelloWorldMiddleware just prints some text to the terminal, we can add it to the bottom of the list since it doesn’t really depend on anything.
On the other hand, if the middleware relied on the user, then we should make sure our middleware is after the LoadUserMiddleware. This way the user is loaded into the request class and then our middleware has access to it. As you can tell, the LoadUserMiddleware is first for exactly that reason.
Now the HTTP middleware is fully registered with Masonite and it will now run on every request. In a bit, we will see what the output will look like. Before we do that, we’ll talk about how to register route middleware.
Route Middleware
Now route middleware again is the same as HTTP middleware, but registering it is a bit different. Right off the bat we can notice that the route middleware is a dictionary. This means we need to bind it to some key.
The naming convention is up to you, but I like to try to keep it to one word. If you need to split into more than one word , we can name it something like hello.world or hello-world. Just be sure not to use the : character since Masonite will splice on that key in our routes file. You’ll see more of what that means in the route section in a little bit.
Using the Middleware
So we have talked about what to use middleware for, the different types of middleware we can create, how to create both of those middleware, and finally how to register both of them with Masonite.
Now we will finally get to how we can use the middleware we created. Now the HTTP middleware, which is the one we put inside the list, is already ready to go. We don’t actually have to do anything further.
Notice we start seeing the hello world and goodbye world print statements before and after our controller methods are hit.
Route middleware on the other hand is a bit different. We will need to use this middleware by specifying the key in our routes file.
This will now run the middleware ONLY for this route and not for any other routes.
Remember before we say to make sure your middleware aliases don’t have a : in the name because Masonite will splice on that? Well this is what that meant. Masonite will splice on the : character and pass all variables after it to the middleware.
Whatever we pass into the route, BOTH the before and after middleware need those two parameters.
As you might have guessed, the parameters are in the same order as you specify them in the routes. So greeting will be Hello and name will be Joe.
Middleware Stacks
Middleware stacks are another simple concept. There will be times when some of your routes look very repetitive with the same middleware over and over again. We can group middleware into middleware “stacks,” or lists of middleware, in order to run all those middleware under one alias.