The Flow of Middleware
In this lesson, we'll learn about the middleware that comes preinstalled within AdonisJS and the flow of this middleware during an HTTP Request at both a global and route-specific scale.
- Author
- Tom Gobich
- Published
- Apr 20
- Duration
- 7m 49s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
The Flow of Middleware
-
(upbeat music)
-
Middleware is a set of functions
-
that we can use to execute code
-
at three different intervals
-
throughout an HTTP request lifecycle.
-
And they're defined within our start directory
-
within our kernel.ts file.
-
If we scroll down a little bit,
-
we're going to see server.use, router.use,
-
as well as router.named.
-
These are the three different intervals
-
with which we can run middleware.
-
And they're executed in the same order
-
that they're listed here.
-
So server middleware is run first,
-
and then it will reach to our router middleware,
-
and lastly, our router.named middleware.
-
Every middleware has a next function within it.
-
And whenever we're working our way up that call tree,
-
we are working from the start of that function
-
up to the next function's call.
-
And then we await the next function,
-
and the middleware pauses there
-
as we continue up that tree.
-
At the top of the tree
-
is where our route handler is executed.
-
So this is where we would dive into, say,
-
our movies index handler for our home page.
-
We'd query our movies,
-
prepare our HTML rendering with EdgeJS,
-
and then return back.
-
And then whenever we return back from this route handler,
-
that's where we begin our descent down the call tree
-
in the inverse order with which we went up it.
-
So if we dive back into our kernel.ts,
-
we will start with our route.named middleware
-
on our way down,
-
then kick into our router middleware,
-
and then lastly, our server middleware.
-
Again, server middleware is middleware that's run
-
regardless of whether or not a registered route
-
matches the request's URL.
-
So if we were to make a request to /test,
-
but we don't have a route defined
-
specifically for our /test,
-
the server middleware will still execute.
-
Our router middleware will run
-
when the request has a registered route
-
that's found for the URL.
-
And then lastly, our named middleware
-
is applied to specific routes.
-
And we use the name,
-
which is the key in this case of this object
-
that we're passing into router.named
-
to apply this middleware to our individual routes.
-
So if we were to use Command + P
-
and dive into our routes file,
-
let's scroll down to our authentication routes,
-
because for these specific routes,
-
whenever a user attempts to request them,
-
if they're logged in,
-
we don't want them to be able to view this page
-
or perform this action.
-
Instead, we want to kick them back to the homepage
-
or something of the sort,
-
rather than showing them this page.
-
And that's exactly what that guest middleware does
-
that we have named within our kernel.ts file.
-
So we can apply the guest middleware
-
to each one of these routes or the route group as a whole.
-
However, whenever we get to our log out point,
-
we'll want to be able to define that route within this group
-
but not apply that middleware to it.
-
So let's individually apply the middleware
-
to each of these four routes that we have here.
-
So to apply a named middleware,
-
we can do .use,
-
and you'll see that this accepts in our middleware.
-
So we can type out middleware
-
and hit tab to import that from our kernel file.
-
Once we do that, we can hit dot,
-
and we're gonna see the named middleware pop up here
-
with an IntelliSense.
-
And let's select our guest middleware,
-
and we'll call this as a method.
-
And there we go.
-
We have just applied our guest middleware
-
to our post login route.
-
Now we haven't set up authentication yet,
-
so we can't quite test this,
-
but let's give that a copy
-
and paste it to the other three here as well.
-
Our red squiggly is gonna show up,
-
but that's just the linter complaining about the line length.
-
Okay, I'm gonna give that a line break in between
-
so that we can tell that there's a difference there.
-
And we've now successfully applied
-
a named middleware to these routes.
-
The other middleware that we have
-
within our kernel.ts file,
-
if we scroll up at the router and at the server level,
-
will execute on their own at a global scale.
-
We don't need to apply them to specific routes.
-
They'll run for all routes,
-
or in the server's case,
-
even for requests that don't match a route.
-
To quickly go over what we have here,
-
the container bindings middleware,
-
as the name suggests,
-
is going to set up our container bindings.
-
And this is a local middleware to our application.
-
You'll see that it's at hash middleware,
-
which is an alias for app middleware.
-
So if we dive into here,
-
we can see our container bindings middleware right there,
-
and we can dive into it.
-
Once we do, we'll see that this is initiated as a class.
-
That's a default export,
-
and it has a handle method inside of it.
-
Handle method is provided as parameters,
-
the HTTP context, as well as a next function.
-
And if we needed to pass in arguments to this middleware,
-
that would come in as the third parameter.
-
But at this level, since we're at our server level here,
-
this is not applicable.
-
And specifically, this middleware is setting up
-
our container bindings for our HTTP context,
-
as well as our logger,
-
and then calling and returning back our next function.
-
And as stated earlier,
-
whenever we're working our way up the call tree,
-
we're going from the start of the function
-
to where we call the next function at.
-
And then we pause at that next function,
-
await for our route handler to be called,
-
and then we'll begin working our way down that call tree
-
and call anything after that next function.
-
So if we wanted to, we could await that next function
-
and then perform something on the way down the tree here.
-
And the only reason we're getting a red squiggly there
-
is because we need to add async.
-
So this portion of the handle method
-
is called before our route handler is executed.
-
And this portion is called
-
after our route handler is executed.
-
So if we need to provide something into our route handler
-
or bind something to our HTTP context for it,
-
we can do that before the next call.
-
And if we need to do anything
-
with the response of our route handler,
-
we could then do that after the next function,
-
something like maybe minifying the HTML.
-
So if we dive back into our kernel,
-
let's say we're working our way through an HTTP request.
-
The server has now executed our container bindings middleware
-
up through and to that next call.
-
And now we're awaiting next.
-
So at that point, we will move on to our static middleware.
-
This one's coming from the AdonisJS static package.
-
And as the name suggests,
-
it's taking care of setting up our static assets
-
and how we handle them.
-
Okay, so now we've executed this one up to the next function
-
and we're now awaiting there as well.
-
We've reached the end of our server middleware.
-
So we'll move on to our router middleware next,
-
where we will first call our body parser middleware.
-
The body parser middleware is in charge of parsing the body
-
just as the name suggests.
-
So it's in charge of actually providing us
-
that request.body object
-
and all of the properties within it
-
that we're sending up with the request.
-
So we've now called this function up to its next function
-
and we're awaiting there as well.
-
We'll then move on to our session middleware,
-
which sets up our session.
-
We've now called that one up to its next function
-
and we're awaiting here as well,
-
where we move into our shield middleware,
-
which is setting up security packages like CSRF protection.
-
Okay, now we're moving on to our initialize auth middleware,
-
which is initializing our authentication
-
just as the name suggests.
-
And we've now reached the end of our router middleware.
-
We then move on into our named or route specific middleware,
-
where with our authentication routes,
-
we're now calling guest.
-
This too is a local middleware.
-
So if we dive into that one as well,
-
we'll see that this is accepting in our HTTP context,
-
a next function, as well as auth guard options
-
as the third parameter here.
-
It will then loop over those guards
-
or just use the default guard set
-
defined within the auth configuration
-
to check and see whether or not any of them
-
have an authenticated user bound to them.
-
If it does, since we're in the guest middleware,
-
we're going to want to point authenticated users
-
away from this request.
-
So we'll stop the request here
-
and redirect the user to that redirect to path,
-
which is defaulted to our homepage here.
-
In the instance that we do have an authenticated user,
-
everything would stop right here.
-
We would not move on to any other middleware.
-
We would not reach our route handler
-
and we would begin our way immediately
-
back down the call tree.
-
If however, we do not have an authenticated user,
-
next would be called and we'd continue our way
-
up the call tree to any additional middleware
-
that might be applicable.
-
In our case, the guest middleware
-
is the last middleware applied
-
since that is the only middleware
-
applying at the route level.
-
So we would then dive into our route handler.
-
And then once the route handler finishes,
-
we would begin our way back down the call tree
-
in the inverse order with which we went up.
-
So we'd start at the route specific level
-
with our guest middleware.
-
And on the way down,
-
we're essentially just resolving the next function.
-
So anything after next gets executed
-
within the middleware that we have.
-
So as we begin our way down the call tree,
-
this is the portion of the middleware that's being applied.
-
This got called on the way up
-
and this is being called on the way down the call tree.
-
So let's dive back into our kernel.
-
We've now finished with our route specific middleware.
-
So we'll go back to our router middleware
-
and go in the inverse order here.
-
So we'll start with our initialize auth,
-
then move into our shield, then our session,
Join The Discussion! (2 Comments)
Please sign in or sign up for free to join in on the dicussion.
guy-aloni
Why do you apply the guest middleware for each route instead of applying it to the entire group?
Please sign in or sign up for free to reply
tomgobich
Hey Guy! I'm applying them here to the individual routes because, in a couple of lessons, we'll be adding a logout route that only authenticated users will be using. So
guest
won't apply to the whole group.Please sign in or sign up for free to reply