In this lesson, we'll practice using another popular type of middleware called Morgan. 1
Afterwards, we'll write our very own custom middleware and then finish off by putting all that knowledge 2
together to create a Band Name Generator. 3
We mentioned that in terms of the types of functionality you see with middleware, you've got pre-processing 4
types. 5
You've got authentication. 6
You've got error handling ones and you've got logging requests. 7
Body-parser belongs to the pre-processing category. 8
So now let's look at a different category of middleware, namely the logging types. 9
One of the most commonly used logging middlewares for Node is a package called morgan, and it comes 10
from the Dexter Show. 11
Morgan Dexter. 12
And you can see just how popular it is always on NPM by looking at the weekly downloads. Almost 4 million 13
weekly downloads. 14
So it's really, really commonly used and it's basically used to log the requests that come in to your 15
server. 16
And in order to use it, all we have to do is to install it onto our server, import it, and then use 17
it as middleware with the app.use() method. 18
Now, morgan has a number of options that you can use to determine how detailed you want the logging 19
to be. 20
But essentially what happens when we use the morgan middleware, is when we send a request to our server, 21
such as if we try to load up the home page by going to localhost:3000, then it's going to hit up our 22
GET route and it's going to send back the words "Hello," 23
but also behind the scenes this middleware function has triggered before it even gets to the app.get() 24
handler and we get an output in our console that has the date and time of the request. 25
It has the type of request that was made. 26
It has the URL of the request, which is to the forward-slash (/) or the root route. 27
The status code of the request, 28
so 200, it was successful and then a whole bunch of other things that we saw previously in our request, 29
such as where did it come from? 30
Well, it was coming from a Mac running on macOS X 10.15.7, and it came from a browser which is Chrome, 31
etcetera, 32
etcetera. 33
So what I want you to do is I want you to pause on this video, take a look through the docs for the 34
NPM package that's called morgan, and take a look at the different Predefined Formats so we can have 35
combined, we can have common, development (dev), short, tiny, 36
and you can see it tells you what is going to be logged, the status, the URL, the method, the response-time, 37
etcetera, and decide whichever one it is that you want. 38
And then using the code that I showed you earlier, I want you to go into index2.js and modify 39
this starting file 40
so that we can start logging using the morgan middleware. 41
I'm going to leave this slide up and I want you to pause the video and see if you can complete this 42
mini-challenge. 43
All right. 44
So this time I'm going to use a different morgan option. Again, 45
I'm going to use the app.use() method in order to use morgan. 46
And then inside some curly braces, I get to specify the format of my output. 47
So I'm going to change it to "tiny" in order to get less stuff out and making sure that I've stopped my 48
server, making sure that I have in fact NPM installed 49
morgan, so that I have the package that I just imported, 50
I'm going to use Nodemon to run my index2.js 51
So now let's go ahead and test this out. 52
So I'm going to open up my Postman and I'm going to hit up the localhost:3000. 53
Let's send a GET request. 54
You can see a GET request was sent to the root route. 55
The result was 200, all successful and that whole process took five milliseconds. 56
Now let's try something else. 57
Let's try a POST request to the /submit. 58
You can see that even though we don't even have a handler to deal with it, because the middleware actually 59
happens before the request reaches any of the handlers, 60
we still have a valid middleware action that's happening, telling me that a post request was submitted 61
to the /submit route. 62
It was a 404 because of course that is not handled and this is how long it took. 63
So have a play around with that. 64
If you use the morgan documentation and you use the require() function, which is fine, it's just a little 65
bit outdated and they could probably update their documentation because we are in fact using 66
module-based ES6 JavaScript so we can actually use the import as we've been using so far. 67
That's just one thing to keep note of. 68
Now we've seen a couple of middlewares, now we've seen body-parser and we've seen morgan just now, 69
what if we wanted to build our own middleware? 70
What does that require? 71
Essentially what happens in all of these middlewares is we use the app.use() method to specify a middleware 72
to use when the request comes in, 73
and inside there, we can pass in a function and it has a request, a response object and a next() method. 74
Because there can be multiple middleware and also because this is something that happens in the middle, 75
the next function basically determines when we should move on from the middleware and continue in the 76
flow of the server handlers. 77
So when should it go to the next function that's in line? 78
So the middleware that we're putting inside the app.use() method can in fact be created from scratch. 79
And it's quite useful to see this, just to know roughly what's actually going behind the scenes with 80
all of these different modules that we're putting in here, like body-parser and 81
morgan. 82
So in this case, all I've got is a function that takes a request, a response object, and also has 83
a next() method. 84
Now when the middleware is activated, in this case, all I'm doing is just doing some logging, so I'm 85
saying log request method and then tap into the req.method property in order to print it out. 86
Finally, we have the next() function, which basically just says, okay, I'm done with all of my middleware 87
functionality, proceed to the next step of handling that request. 88
Now if there is another middleware here, 89
then that is where that next() is going to go to. 90
It's going to go to the next app.use, which is why it's really important in Express the order that 91
you put your middleware. 92
If you want your request to be authenticated before you log the request or before you parse the request, 93
then you have to think about the order that it's going in in your code file. 94
But once it's done with all the middleware, then the next function will actually go to your request 95
handlers such as our app.get or our app.post. 96
So what I want you to do is to take a look at this particular slide and think about how you can implement 97
it in your own code. 98
Now in this case, all I'm doing is just logging the req.method, but I want you to log the 99
req.method, but also the URL of the request and you can get access to these through req.method, but 100
also req.url. 101
Open up index3.js, modify the code here so that you can create your own logging middleware and 102
as an extra challenge, I don't want you to have the middleware like what we had in the example, which 103
is where we've got the function inside app.use(), I want you to make it look like the other middleware 104
that we've used. 105
Remember with body-parser, all we did was app.use() and then we just said body-parser, blah blah blah 106
blah, blah. 107
And with morgan it was again going into here. 108
So what your app.use() should look like is it should look like this, making sure that this line of code 109
actually works. 110
I want you to write the middleware function that's going to log the request URL and the request method 111
into the console. 112
Pause the video and complete this challenge. 113
All right. 114
So we know that we need to create a middleware function called logger in order for this line of code 115
to work. 116
So let's do that now. 117
It's going to have the request, response and next and then we're going to console log a bunch of things. 118
Now, how you format your console log is totally up to you, but I'm going to say "Request method" and 119
then afterwards is going to come the "req.method" property, 120
and then I'm also going to console log the "req.url" and I'll change that here as well. 121
And then finally, we're going to need the next() function to say that this function should continue on 122
to the next thing. 123
So let's go ahead and stop our server. 124
Let's use our Nodemon to run index3.js and now let's make some requests. 125
So let's make a GET request. 126
You can see the Request Method and the Request URL. 127
Let's try our POST method, you can see the Request Method and the URL. 128
So we've actually replicated some of the functionality of morgan by creating this middleware ourselves 129
and then using the app.use() method, we're able to specify the middleware that we want to be implemented 130
before we end up in the route handlers. 131
Now remember what I said about the next() method. 132
It's really common that people forget to use it in the middleware and this is what would happen if you 133
did that. 134
So let's make a Send request. 135
You can see it's just hanging, right? 136
Even though we've got all of these things that we wanted, console logged, logged, 137
but if we actually try to go to our home page localhost, then it's actually not going to load because 138
it never manages to reach this handler because right here we need that method to happen before we can 139
actually hit up that handler that sends back whatever it is that we need to the client. 140
So the order of things really becomes very clear when you omit or when you add in that next function 141
in the middleware. 142
All that's left to do now is to complete the coding exercise for this lesson and to prove that you've 143
learned all the things that we talked about, which is a lot in this lesson. 144
So putting all of your knowledge together, we're going to create the Bandname Generator. Again, going 145
back to your 3.4 Middleware, you can see that inside index4.js, 146
we've got everything set up for you to get started. 147
It's just a simple Express Node Server, but what you're going to have to do is to go ahead and install 148
the right packages, to import the right modules and then to be able to serve up the index.html website 149
when a GET request is made to our server. 150
So we did that when we did index1.js, remember? Earlier? And you can review the code from over there 151
and you can even copy and paste the code in because my stance on copy and pasting code is you're never 152
going to be able to memorize word for word what a lot of these methods and things are going to look 153
like, and it's perfectly acceptable to copy and paste code. 154
But, but this is a huge but, you have to understand what the code that you copied does, what is its 155
function and not just blindly copy and paste code from the internet, but we've already gone through 156
it, so you should be able to review index1.js, add in the part of code that are required in order 157
to serve up the website and also you should be able to get the middleware working so that we can actually 158
parse the information that's coming in from the form in our Bandname Generator. The Street name and 159
the Pet name, so that when the submit button is pressed and a POST request comes over to our server, 160
we know how to handle it. 161
And then finally, what we're going to do is we're going to do a res.send to send back the result of 162
the combined word. 163
So the first part is the Street name and the second part is their Pet name. 164
If you go ahead and use Nodemon to run the solution4.js, then if you go over to our localhost 165
you can see how it should function. 166
So let's put in my values here into the two inputs, click submit and then we get back a h2 and a 167
h2. 168
And this is just an emoji which you can even copy and paste into your code if you wish. 169
And then this is the combined value of those two inputs that I put in just now. 170
So if I change this to Angela and then hit submit, you can see this is reacting to my HTML form. 171
That's the goal. 172
Pause the video and give this challenge a go. 173
Now, this combines a lot of stuff that we did today. 174
And what I want you to do if you got stuck, is to take a look at solution4.js, the solution code 175
for the exercise and see where you might have gone wrong. 176
The first thing we need to do is to add our route handlers. 177
We have an app.get() on our root route that is going to send the file, which is our index.html inside 178
the public folder. 179
Remember to do that, we need the full-file path and to get the full path path we need this directory 180
name constant. 181
So you can simply have copied these three lines from index1 and that is going to get you that directory 182
name which you can append to the rest of the path, which is the public folder index.html. 183
And then once you've done that, the next part is to actually test it out and make sure that when you 184
go to your localhost:3000, you actually see that file being served up using the Send file. 185
So always break down a complex task into smaller tasks and test frequently. 186
Now once that's up and running, then we need to install and get the body-parser middleware to work. 187
We'll import body-parser from the body-parser module, and then we're going to use the app.use() to be able 188
to parse urlencoded data. 189
And this again, you could have simply just copied over from the solution1. 190
This is something that we already did before and because you now know what it does, you don't have 191
to memorize it letter by letter and make typos and struggle in that kind of way. 192
This is something that you can simply keep save on your computer and refer to it whenever you need this 193
functionality because now you understand what it does. 194
Once we have that middleware in place, then we can go ahead and process the request body that we're 195
getting through the HTML form. 196
In my case, I created my own middleware called bandNameGenerator, 197
so another preprocessor that's going into our server. 198
So once we've parsed the information, then we generate the band name, 199
this function basically takes the request, takes the first part, which is the Street, and then adds 200
it to the Pet name and then hits up the next() part of our server. 201
And this app.use() is where this function is called. 202
So this is the first middleware that happens. 203
We parse the information, then we generate the name from the req.body that the user entered, and 204
then our server determines which route needs to be hit up. 205
If it was a POST request that came in to the submit route, then we're going to res.send() the actual band 206
name back to the user, h1 and a h2. 207
And that is how we end up with this website. 208
If you didn't create a separate middleware and you simply put this inside the POST route, that's also 209
perfectly fine. 210
It really doesn't matter. 211
I just wanted to demonstrate to you one potential option. 212
You could have simply put all of this in here and then just paste it like this. 213
This is in fact less lines of code, but it's always good to know other options, right? 214
And plus, I get to demonstrate to you what happens if we actually change the order of our middleware. 215
So if by accident I put my body-parser middleware below my band generator middleware, then this is 216
what's going to happen when I go to my website. 217
So let's put in our Street name, let's put in our Pet name, hit submit. 218
We get errors, can't read properties of undefined. 219
Why is it undefined? 220
Well, it's because we're trying to access the req.body here, which is the first middleware. 221
But req.body doesn't exist yet because we haven't parsed the incoming request. 222
Remember, middleware order matters a huge deal and I just wanted to be able to demonstrate that to 223
you. 224
Hopefully, the rest of the code is pretty clear and you managed to get your version of bandNameGenerator 225
to work. 226
Once you're ready, head over to the next lesson where we've got the final programming challenge for 227
this section. 228
So I'll see you there.