In this lesson, we'll learn about the two different types of middleware, global middleware and registered middleware. We'll also take a deep dive into how they play into the flow of an AdonisJS Request.
🥁 Subscribe To Stay Notified For New Lessons:
https://www.youtube.com/adocasts?sub_confirmation=1
📺 View on YouTube:
https://www.youtube.com/watch?v=IZ_LjMPiVMg
👨💻 Find The Code For This Lesson Here:
https://github.com/adocasts/lets-learn-adonis-5
📚 Chapters:
- Introducing Middleware
- Types of Middleware
- Defining Our First Middleware
- Understanding the Next Function
- The Middleware Mountain
- Making A Middleware
- Global Middleware
- Terminating/Redirecting A Request
- Named Middleware
- Middleware Guards (Parameters)
- Registering Multiple Route Middleware
- Outro
📜 Transcript:
middleware is a function you can call
after your request matches its route but
before the route actually calls and
executes its route Handler being the
highlighted section here within this
middleware function is where we can
perform checks to verify whether or not
the user should actually have permission
to view or perform some action within
our route in addition to that we can
perform a plethora of other things
within middleware as well including
redirecting a user to a correct page if
they accidentally hit some old page or
something of the sort pre-populating our
request with some data that we will need
maybe throughout our entire application
checking for specific headers that maybe
we'll want to append on to our HTTP
context and those are all checks that
you might want to perform on the way up
so whenever we're receiving a request
using middleware you can also do the
inverse and mutate a response so that
grants you the ability to also perform
actions like minifying your HTML prior
to sending it off to the browser or
injecting your view state with a
specific set of properties so there's
two different types of middleware there
is the middleware that runs globally so
this is going to be middleware that's
executed regardless of what route the
user requests and then there's also
named or registered middleware as well
so these are middleware that are
specifically bound to routes and they'll
only execute on those routes that
they're bound to in this most simplistic
form a middleware is going to be bound
just by calling the middleware method
and this can either accept a named
middleware which we'll go over here in a
second or an actual callback function
that acts as the middleware itself the
first argument to the middleware is
going to be our HTTP context and the
second is going to be a function called
Next this next function is actually
vital to the execution of our request so
let's go ahead and take a look at what
our middleware looks like without that
next function being called so that we
can better understand what exactly it's
doing so let's go and apply some console
logs here so let's do console log first
middleware and then within our route
Handler let's do console log route
Handler let's give that a save and let's
go ahead and boot our server up so let's
do npm run Dev and let's give our
browser a refresh you'll notice that we
don't see that it works page we don't
see our welcome HTML at all all that we
get is this blank page and the reason
for this is if we inspect our terminal
we only have that first middleware
console log we're never actually
reaching the routes Handler so if we
jump back into our code base we're never
reaching this method right here and
that's because we're not calling this
next function within middleware this
next function is what gives Adonis
permission to move onward beyond our
middleware and into our route Handler
visually you can think of this kind of
like a mountain so at the ground level
our request matches the route and it's
Global middleware are executed if there
are any each step up the mountain is
each middleware that we have that needs
to execute for the route once we reach
the peak of the mountain that's our
actual route Handler highlighted here
each of those middlewares that got us up
the mountain are awaiting the execution
and the finish of our route Handler from
the peak of the mountain once that's
completed we'll then begin to work our
way down the mountain calling each of
our middleware in the descending fashion
of what they're executed all the way
until we reach the ground floor yet
again at which point our request will
end so let's go ahead and run through
that flow so that we can better
understand it so let's go ahead and
await our next function so that we're
actually getting to our welcome page
there it is and let's take a look at the
console there so you can see now we have
our first middleware and our route
handle are being called if we change
this console log to first middleware
before next copy this paste this and
change it to after next we can chain
multiple middleware off of each other as
much as we need so let's go ahead and
apply three and let's do second
middleware before next second middleware
after next third middleware before next
and third middleware after next let's
give that a save jump back into our
browser give it a refresh and check out
our terminal so here you can kind of
visualize what's going on with our
Mountain so as we call our middleware we
are taking a step up our mountains so we
have our first middleware before next
our second middleware before next our
third middleware before next and then we
reach the mountain peak with our route
Handler and then we begin to descend our
way down the mountain after the route
Handler is finished by going and
descending order of the middleware as
they're registered so we then we go
third middleware after next second
middleware after next and then back down
to the first middleware after next
you'll also notice that the middleware
are executed in the exact order that
they're defined on our route so if we
jump back to our text editor here we go
first second and third in that order and
then as we work our way down the
mountain we go in descending order so
third second and then back the first so
so far we've been working with
middleware specifically registered and
bound to this route let's go ahead and
add a global middleware into the mix and
see how that differs so let's go ahead
and stop our server and let's run node
Ace within here you'll notice underneath
the make commands that we have a make
middleware method that we can execute to
actually create a middleware so let's do
node Ace make middleware and let's call
this something like authorize so that's
going to create our middleware inside of
our app directory under underneath a new
middleware directory and call our file
authorize.ts it's also going to plop
this info panel on our screen saying to
open the start.kernel.ts and register
our middleware this kernel.ts file is
where all of our middleware will be
registered if they're not bound directly
to a route as we were previously doing
inside of our rails.ts file here this
includes both Global middleware as you
can see we already have one Global
middleware registered called our body
parser this middleware in particular is
responsible for grabbing our body
parsing it out so that we can actually
grab particular properties off of our
request body and down underneath our
Global middleware would be our named
middleware and this is where we can
register specific names to middleware
files as well and then bind them to
routes as we're doing with our callback
function just instead of actually
providing a callback function we would
just need to provide the name Alias so
let's go and take our authorize function
and register it as a global middleware
this will mean that it will run for
every single HTTP request applicable to
our server so to register this we will
go into app we will go into middleware
and then we will call our authorize file
so now it's going to get called for
every single request for our server if
we actually dive into our app middleware
authorize file you'll see that we are
greeted with an exported default class
called authorize and this authorized
class has a single function called
handle within it that looks very similar
to the Callback function that we're
using directly off of our route
definition where the first argument is
going to be our HTTP context and the
second argument is going to be that next
function so just as we were doing with
the middleware that we bound directly to
our route let's go ahead and do
console.log authorize before next and
console.log authorize after next let's
give that a save we don't need to
register this to the route remember it's
a global middleware so it's just
automatically going to run jump back
into our browser first boot our server
back up then jump back into our browser
give it a refresh and you can see now we
added another layer to our Mountain so
our Mountain just got slightly taller so
as mentioned previously that Global
middleware will run prior to any
middleware directly registered to the
route so we have authorized before next
then we go into our middleware directly
bound to the the route so we have first
middleware before next then second and
third then we reach the peak with our
route Handler then we climb our way back
down by going third second first and
then finally our Global middleware of
authorized again not labeled here is
that body parts or middleware that we
have that automatically came registered
so that's actually outside of our
authorized so we actually have body
parser then authorized then authorized
then body parser on our way back down so
on the way up our Mountain if at any
point you find that you don't want the
user to continue onward and end up
reaching the peak with our route Handler
what you can do is for example within
our authorized middleware here we can
grab the response off of our HTTP
context and we can use this to perform
some type of check now we don't really
have anything to check against here so
I'm just going to do if true to make
sure this gets matched and if whatever
we need to check within this check does
come back truthy to where we need to end
the request for the user prematurely and
not allow them to reach the route
Handler then we would want to return
back so that this next function does not
get called Remember remember the next
function is what's going to allow the
user to continue onward beyond the
middleware so if we stop the user from
reaching next we in Turn end the request
for them where we can then response Dot
and we can redirect them to another
route if applicable so for example if
this were an auth middleware and we
wanted the user to be authenticated to
continue onward if they were not
authenticated we could redirect them
here to the login page or we can just
call unauthorized to end their session
and give them back an error of your not
authorized so if we save this give our
browser a refresh you'll see that we now
get that you're not authorized error
because true is true but if we take a
look at our console logs we stop at that
authorized before next call and we do
not continue onward if however we take
this if statement and move it below our
next call give that a save come back
into our browser refresh we still see
that you're not authorized but if we
check that our console logs here you'll
see that we go all the way through our
Mountain almost back down to ground
floor but we don't quite reach it and
it's at that second after next call for
authorize that we then get kicked out
and this is why you always want to
perform your checks prior to that next
call because we just ran through a bunch
of unnecessary code running unnecessary
resources on our server and wasting
milliseconds of time for our user to
tell them that they're not authorized to
perform some action so always perform
your checks prior to that next call only
use after next anytime you need to
mutate the response in some way and I'm
going to go ahead and get rid of that
check and alternatively here within our
kernel.ts we can take this what's now a
global middleware remove it from here
and change it into a named middleware so
we can come back down to our register
named middleware name it authorize and
Define it just like so now since it's no
longer a global middleware it will only
execute on the routes where the
middleware authorize is registered so
since it's not registered currently to
any route if we execute this we come all
the way through our request and if we
check our console logs authorize is
nowhere to be found if however we come
back into our routes and we put it first
so if we do middleware authorize give
that a save refresh and if we check our
terminal again you'll see that it is now
back and remember middleware will run in
the order that they are registered so if
we move this to the bottom it will move
its position on our Mountain from being
at the base floor to being right there
near the peak so let's say that we need
to provide some type of a role to our
authorized method to say authorize
whether or not the user has the
particular roles that we're providing
here we can provide guard information or
parameters to this middleware by adding
a suffix of a colon and a commonly
limited list of any string information
that we need to provide to this
middleware so we can provide for example
the roles that we might want to allow
into these route so for this route we
could do authorize admin and moderator
and we could have another route maybe
guest I'm just going to return back a
string of guests there with a middleware
for authorize that will check whether or
not the user has the role of guest so
now we have one middleware method that
can perform several different checks by
accepting guard information and remember
here this is a comma delimited list but
a Adonis will take that and whenever it
takes it and provides it into our actual
authorized handle method it will provide
it as the third argument to the Sandal
method as guards and it will split that
comma The Limited list into a string
array so if we console.log our guards
here give this a save jump back into our
browser refresh check our terminal you
can see our authorize now has our guards
and its split our admin and moderator
commodity limited list into an array
likewise if we head over to guest we get
back that guest string that I returned
but we also have that guard set to an
array of guests as well and if we come
back here and we leave the guard off all
together give our page a refresh jump
back into our terminal you can see the
guard comes through as an empty array
now if you have multiple named
middleware you don't need to chain them
off with the middleware call one after
another as we are here instead you can
just provide an array to the middleware
method and I'm just going to call the
same one twice with a different guard
here but you don't need to chain
middleware one after another you can
just provide an array of the named
middleware that you actually want to
execute give that a save jump back into
our browser refresh and you can see
authorized it's called twice with two
different guard sets but it's still
called each time so that's an
alternative and cleaner way to register
your routes there as well and I believe
this would work with the function
approach as well so if we tack the
function onto the end of here give that
a save jump back into our browser
refresh and there you go it does indeed
so now we have that third middleware in
there as well despite it being a
callback function so you have these two
different approaches that you can
utilize to call multiple middleware that
are global
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!