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,
-
lastly, our body parser.
-
And now we've finished our router.
-
So we'll move up to our server level middleware
-
in the same inverse order.
-
So we'll start with static and lastly,
-
go to our container bindings.
-
Once we've reached this point,
-
the response is ready
-
and it will then be kicked back to the browser.
-
And that is the full flow of middleware
-
as we have it currently within our application.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
Logging Out An Authenticated User2m 24s
-
Logging In An Existing User6m 54s
-
Remembering A User's Authenticated Session6m 55s
-
Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!