Playing Next Lesson In
seconds

The Middleware Mountain

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.

Created by
@tomgobich
Published

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:
00:00 - Introducing Middleware
00:55 - Types of Middleware
01:15 - Defining Our First Middleware
01:34 - Understanding the Next Function
02:30 - The Middleware Mountain
04:33 - Making A Middleware
05:50 - Global Middleware
07:20 - Terminating/Redirecting A Request
09:26 - Named Middleware
10:10 - Middleware Guards (Parameters)
11:44 - Registering Multiple Route Middleware
12:33 - Outro


📜 Transcript:

0:00

middleware is a function you can call

0:01

after your request matches its route but

0:04

before the route actually calls and

0:07

executes its route Handler being the

0:09

highlighted section here within this

0:10

middleware function is where we can

0:12

perform checks to verify whether or not

0:14

the user should actually have permission

0:16

to view or perform some action within

0:18

our route in addition to that we can

0:20

perform a plethora of other things

0:22

within middleware as well including

0:23

redirecting a user to a correct page if

0:26

they accidentally hit some old page or

0:28

something of the sort pre-populating our

0:29

request with some data that we will need

0:31

maybe throughout our entire application

0:33

checking for specific headers that maybe

0:36

we'll want to append on to our HTTP

0:37

context and those are all checks that

0:39

you might want to perform on the way up

0:40

so whenever we're receiving a request

0:42

using middleware you can also do the

0:44

inverse and mutate a response so that

0:47

grants you the ability to also perform

0:49

actions like minifying your HTML prior

0:51

to sending it off to the browser or

0:53

injecting your view state with a

0:55

specific set of properties so there's

0:57

two different types of middleware there

0:59

is the middleware that runs globally so

1:01

this is going to be middleware that's

1:02

executed regardless of what route the

1:05

user requests and then there's also

1:06

named or registered middleware as well

1:09

so these are middleware that are

1:11

specifically bound to routes and they'll

1:13

only execute on those routes that

1:15

they're bound to in this most simplistic

1:16

form a middleware is going to be bound

1:19

just by calling the middleware method

1:21

and this can either accept a named

1:23

middleware which we'll go over here in a

1:24

second or an actual callback function

1:26

that acts as the middleware itself the

1:28

first argument to the middleware is

1:29

going to be our HTTP context and the

1:31

second is going to be a function called

1:33

Next this next function is actually

1:35

vital to the execution of our request so

1:38

let's go ahead and take a look at what

1:40

our middleware looks like without that

1:41

next function being called so that we

1:43

can better understand what exactly it's

1:44

doing so let's go and apply some console

1:46

logs here so let's do console log first

1:50

middleware and then within our route

1:52

Handler let's do console log route

1:54

Handler let's give that a save and let's

1:56

go ahead and boot our server up so let's

1:59

do npm run Dev and let's give our

2:01

browser a refresh you'll notice that we

2:04

don't see that it works page we don't

2:05

see our welcome HTML at all all that we

2:08

get is this blank page and the reason

2:10

for this is if we inspect our terminal

2:12

we only have that first middleware

2:13

console log we're never actually

2:15

reaching the routes Handler so if we

2:16

jump back into our code base we're never

2:18

reaching this method right here and

2:21

that's because we're not calling this

2:22

next function within middleware this

2:24

next function is what gives Adonis

2:26

permission to move onward beyond our

2:28

middleware and into our route Handler

2:30

visually you can think of this kind of

2:31

like a mountain so at the ground level

2:33

our request matches the route and it's

2:36

Global middleware are executed if there

2:38

are any each step up the mountain is

2:40

each middleware that we have that needs

2:42

to execute for the route once we reach

2:44

the peak of the mountain that's our

2:46

actual route Handler highlighted here

2:48

each of those middlewares that got us up

2:50

the mountain are awaiting the execution

2:52

and the finish of our route Handler from

2:54

the peak of the mountain once that's

2:55

completed we'll then begin to work our

2:57

way down the mountain calling each of

2:59

our middleware in the descending fashion

3:01

of what they're executed all the way

3:03

until we reach the ground floor yet

3:04

again at which point our request will

3:06

end so let's go ahead and run through

3:08

that flow so that we can better

3:09

understand it so let's go ahead and

3:11

await our next function so that we're

3:13

actually getting to our welcome page

3:15

there it is and let's take a look at the

3:17

console there so you can see now we have

3:19

our first middleware and our route

3:20

handle are being called if we change

3:22

this console log to first middleware

3:23

before next copy this paste this and

3:27

change it to after next we can chain

3:29

multiple middleware off of each other as

3:31

much as we need so let's go ahead and

3:32

apply three and let's do second

3:35

middleware before next second middleware

3:37

after next third middleware before next

3:39

and third middleware after next let's

3:42

give that a save jump back into our

3:43

browser give it a refresh and check out

3:46

our terminal so here you can kind of

3:47

visualize what's going on with our

3:49

Mountain so as we call our middleware we

3:51

are taking a step up our mountains so we

3:53

have our first middleware before next

3:54

our second middleware before next our

3:56

third middleware before next and then we

3:58

reach the mountain peak with our route

3:59

Handler and then we begin to descend our

4:02

way down the mountain after the route

4:03

Handler is finished by going and

4:05

descending order of the middleware as

4:08

they're registered so we then we go

4:09

third middleware after next second

4:10

middleware after next and then back down

4:12

to the first middleware after next

4:14

you'll also notice that the middleware

4:16

are executed in the exact order that

4:18

they're defined on our route so if we

4:20

jump back to our text editor here we go

4:23

first second and third in that order and

4:27

then as we work our way down the

4:28

mountain we go in descending order so

4:30

third second and then back the first so

4:32

so far we've been working with

4:34

middleware specifically registered and

4:36

bound to this route let's go ahead and

4:38

add a global middleware into the mix and

4:40

see how that differs so let's go ahead

4:42

and stop our server and let's run node

4:44

Ace within here you'll notice underneath

4:46

the make commands that we have a make

4:48

middleware method that we can execute to

4:50

actually create a middleware so let's do

4:52

node Ace make middleware and let's call

4:54

this something like authorize so that's

4:57

going to create our middleware inside of

4:58

our app directory under underneath a new

5:00

middleware directory and call our file

5:02

authorize.ts it's also going to plop

5:04

this info panel on our screen saying to

5:06

open the start.kernel.ts and register

5:08

our middleware this kernel.ts file is

5:11

where all of our middleware will be

5:12

registered if they're not bound directly

5:15

to a route as we were previously doing

5:17

inside of our rails.ts file here this

5:19

includes both Global middleware as you

5:21

can see we already have one Global

5:22

middleware registered called our body

5:24

parser this middleware in particular is

5:27

responsible for grabbing our body

5:29

parsing it out so that we can actually

5:30

grab particular properties off of our

5:32

request body and down underneath our

5:34

Global middleware would be our named

5:37

middleware and this is where we can

5:38

register specific names to middleware

5:40

files as well and then bind them to

5:42

routes as we're doing with our callback

5:45

function just instead of actually

5:46

providing a callback function we would

5:48

just need to provide the name Alias so

5:50

let's go and take our authorize function

5:52

and register it as a global middleware

5:53

this will mean that it will run for

5:55

every single HTTP request applicable to

5:57

our server so to register this we will

5:59

go into app we will go into middleware

6:01

and then we will call our authorize file

6:03

so now it's going to get called for

6:04

every single request for our server if

6:06

we actually dive into our app middleware

6:07

authorize file you'll see that we are

6:09

greeted with an exported default class

6:11

called authorize and this authorized

6:13

class has a single function called

6:14

handle within it that looks very similar

6:16

to the Callback function that we're

6:17

using directly off of our route

6:18

definition where the first argument is

6:20

going to be our HTTP context and the

6:22

second argument is going to be that next

6:23

function so just as we were doing with

6:26

the middleware that we bound directly to

6:28

our route let's go ahead and do

6:29

console.log authorize before next and

6:32

console.log authorize after next let's

6:35

give that a save we don't need to

6:36

register this to the route remember it's

6:38

a global middleware so it's just

6:39

automatically going to run jump back

6:41

into our browser first boot our server

6:42

back up then jump back into our browser

6:44

give it a refresh and you can see now we

6:46

added another layer to our Mountain so

6:48

our Mountain just got slightly taller so

6:50

as mentioned previously that Global

6:52

middleware will run prior to any

6:53

middleware directly registered to the

6:55

route so we have authorized before next

6:57

then we go into our middleware directly

6:59

bound to the the route so we have first

7:01

middleware before next then second and

7:03

third then we reach the peak with our

7:04

route Handler then we climb our way back

7:06

down by going third second first and

7:08

then finally our Global middleware of

7:09

authorized again not labeled here is

7:11

that body parts or middleware that we

7:13

have that automatically came registered

7:15

so that's actually outside of our

7:16

authorized so we actually have body

7:17

parser then authorized then authorized

7:20

then body parser on our way back down so

7:22

on the way up our Mountain if at any

7:24

point you find that you don't want the

7:26

user to continue onward and end up

7:28

reaching the peak with our route Handler

7:30

what you can do is for example within

7:32

our authorized middleware here we can

7:34

grab the response off of our HTTP

7:36

context and we can use this to perform

7:38

some type of check now we don't really

7:40

have anything to check against here so

7:42

I'm just going to do if true to make

7:44

sure this gets matched and if whatever

7:46

we need to check within this check does

7:48

come back truthy to where we need to end

7:50

the request for the user prematurely and

7:52

not allow them to reach the route

7:54

Handler then we would want to return

7:55

back so that this next function does not

7:58

get called Remember remember the next

8:00

function is what's going to allow the

8:01

user to continue onward beyond the

8:03

middleware so if we stop the user from

8:05

reaching next we in Turn end the request

8:07

for them where we can then response Dot

8:10

and we can redirect them to another

8:11

route if applicable so for example if

8:14

this were an auth middleware and we

8:16

wanted the user to be authenticated to

8:18

continue onward if they were not

8:19

authenticated we could redirect them

8:21

here to the login page or we can just

8:23

call unauthorized to end their session

8:25

and give them back an error of your not

8:28

authorized so if we save this give our

8:31

browser a refresh you'll see that we now

8:33

get that you're not authorized error

8:34

because true is true but if we take a

8:37

look at our console logs we stop at that

8:39

authorized before next call and we do

8:41

not continue onward if however we take

8:43

this if statement and move it below our

8:45

next call give that a save come back

8:47

into our browser refresh we still see

8:49

that you're not authorized but if we

8:50

check that our console logs here you'll

8:52

see that we go all the way through our

8:53

Mountain almost back down to ground

8:55

floor but we don't quite reach it and

8:57

it's at that second after next call for

8:59

authorize that we then get kicked out

9:01

and this is why you always want to

9:03

perform your checks prior to that next

9:05

call because we just ran through a bunch

9:07

of unnecessary code running unnecessary

9:09

resources on our server and wasting

9:11

milliseconds of time for our user to

9:13

tell them that they're not authorized to

9:15

perform some action so always perform

9:16

your checks prior to that next call only

9:19

use after next anytime you need to

9:20

mutate the response in some way and I'm

9:23

going to go ahead and get rid of that

9:24

check and alternatively here within our

9:26

kernel.ts we can take this what's now a

9:28

global middleware remove it from here

9:30

and change it into a named middleware so

9:32

we can come back down to our register

9:34

named middleware name it authorize and

9:36

Define it just like so now since it's no

9:38

longer a global middleware it will only

9:40

execute on the routes where the

9:42

middleware authorize is registered so

9:45

since it's not registered currently to

9:46

any route if we execute this we come all

9:49

the way through our request and if we

9:50

check our console logs authorize is

9:52

nowhere to be found if however we come

9:54

back into our routes and we put it first

9:56

so if we do middleware authorize give

9:58

that a save refresh and if we check our

10:00

terminal again you'll see that it is now

10:02

back and remember middleware will run in

10:04

the order that they are registered so if

10:05

we move this to the bottom it will move

10:07

its position on our Mountain from being

10:09

at the base floor to being right there

10:11

near the peak so let's say that we need

10:13

to provide some type of a role to our

10:15

authorized method to say authorize

10:17

whether or not the user has the

10:19

particular roles that we're providing

10:20

here we can provide guard information or

10:22

parameters to this middleware by adding

10:25

a suffix of a colon and a commonly

10:27

limited list of any string information

10:29

that we need to provide to this

10:31

middleware so we can provide for example

10:32

the roles that we might want to allow

10:35

into these route so for this route we

10:37

could do authorize admin and moderator

10:39

and we could have another route maybe

10:41

guest I'm just going to return back a

10:43

string of guests there with a middleware

10:45

for authorize that will check whether or

10:48

not the user has the role of guest so

10:49

now we have one middleware method that

10:52

can perform several different checks by

10:54

accepting guard information and remember

10:56

here this is a comma delimited list but

10:59

a Adonis will take that and whenever it

11:01

takes it and provides it into our actual

11:03

authorized handle method it will provide

11:04

it as the third argument to the Sandal

11:06

method as guards and it will split that

11:09

comma The Limited list into a string

11:12

array so if we console.log our guards

11:14

here give this a save jump back into our

11:16

browser refresh check our terminal you

11:19

can see our authorize now has our guards

11:21

and its split our admin and moderator

11:23

commodity limited list into an array

11:26

likewise if we head over to guest we get

11:29

back that guest string that I returned

11:31

but we also have that guard set to an

11:34

array of guests as well and if we come

11:36

back here and we leave the guard off all

11:38

together give our page a refresh jump

11:40

back into our terminal you can see the

11:41

guard comes through as an empty array

11:43

now if you have multiple named

11:45

middleware you don't need to chain them

11:47

off with the middleware call one after

11:48

another as we are here instead you can

11:51

just provide an array to the middleware

11:53

method and I'm just going to call the

11:54

same one twice with a different guard

11:56

here but you don't need to chain

11:58

middleware one after another you can

12:00

just provide an array of the named

12:01

middleware that you actually want to

12:02

execute give that a save jump back into

12:04

our browser refresh and you can see

12:06

authorized it's called twice with two

12:08

different guard sets but it's still

12:09

called each time so that's an

12:11

alternative and cleaner way to register

12:13

your routes there as well and I believe

12:15

this would work with the function

12:17

approach as well so if we tack the

12:19

function onto the end of here give that

12:21

a save jump back into our browser

12:23

refresh and there you go it does indeed

12:25

so now we have that third middleware in

12:27

there as well despite it being a

12:29

callback function so you have these two

12:30

different approaches that you can

12:31

utilize to call multiple middleware that

12:33

are global

Join the Discussion 0 comments

Create a free account to join in on the discussion
robot comment bubble

Be the first to comment!