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.

Published
Nov 06, 22
Duration
12m 44s

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

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)

Please sign in or sign up for free to join in on the dicussion.

robot comment bubble

Be the first to Comment!

Playing Next Lesson In
seconds