In this lesson, we'll practice using another popular type of middleware called Morgan.
Afterwards, we'll write our very own custom middleware and then finish off by putting all that knowledge
together to create a Band Name Generator.
We mentioned that in terms of the types of functionality you see with middleware, you've got pre-processing
types,
you've got authentication,
you've got error-handling ones and you've got logging requests.
Body-parser belongs to the pre-processing category.
So now let's look at a different category of middleware, namely the logging types.
One of the most commonly used logging middlewares for Node is a package called morgan, and it comes
from the Dexter Show.
Morgan Dexter.
And you can see just how popular it is always on NPM by looking at the weekly downloads. Almost 4 million
weekly downloads.
So it's really, really commonly used and it's basically used to log the requests that come in to your
server.
And in order to use it, all we have to do is to install it onto our server, import it, and then use
it as middleware with the app.use() method.
Now, morgan has a number of options that you can use to determine how detailed you want the logging
to be.
But essentially what happens when we use the morgan middleware, is when we send a request to our server,
such as if we try to load up the home page by going to localhost:3000, then it's going to hit up our
GET route and it's going to send back the words "Hello,"
but also behind the scenes this middleware function has triggered before it even gets to the app.get()
handler and we get an output in our console that has the date and time of the request.
It has the type of request that was made.
It has the URL of the request, which is to the forward-slash (/) or the root route.
The status code of the request,
so 200, it was successful and then a whole bunch of other things that we saw previously in our request,
such as where did it come from?
Well, it was coming from a Mac running on macOS X 10.15.7, and it came from a browser which is Chrome,
etcetera,
etcetera.
So what I want you to do is I want you to pause on this video, take a look through the docs for the
NPM package that's called morgan, and take a look at the different Predefined Formats. So we can have
combined, we can have common, development (dev), short, tiny,
and you can see it tells you what is going to be logged, the status, the URL, the method, the response-time,
etcetera, and decide whichever one it is that you want.
And then using the code that I showed you earlier, I want you to go into index2.js and modify
this starting file
so that we can start logging using the morgan middleware.
I'm going to leave this slide up and I want you to pause the video and see if you can complete this
mini-challenge.
All right.
So this time I'm going to use a different morgan option. Again,
I'm going to use the app.use() method in order to use morgan.
And then inside some curly braces, I get to specify the format of my output.
So I'm going to change it to "tiny" in order to get less stuff out. And making sure that I've stopped my
server, making sure that I have in fact npm installed
morgan, so that I have the package that I just imported,
I'm going to use Nodemon to run my index2.js
So now let's go ahead and test this out.
So I'm going to open up my Postman and I'm going to hit up the localhost:3000.
Let's send a GET request.
You can see a GET request was sent to the root route.
The result was 200, all successful and that whole process took five milliseconds.
Now let's try something else.
Let's try a POST request to the /submit.
You can see that even though we don't even have a handler to deal with it, because the middleware actually
happens before the request reaches any of the handlers,
we still have a valid middleware action that's happening, telling me that a POST request was submitted
to the /submit route.
It was a 404, because of course that is not handled and this is how long it took.
So have a play around with that.
If you use the morgan documentation and you use the require() function, which is fine, it's just a little
bit outdated and they could probably update their documentation because we are in fact using
module-based ES6 JavaScript so we can actually use the import as we've been using so far.
That's just one thing to keep note of.
Now we've seen a couple of middlewares, now we've seen body-parser and we've seen morgan just now,
what if we wanted to build our own middleware?
What does that require?
Essentially what happens in all of these middlewares is we use the app.use() method to specify a middleware
to use when the request comes in,
and inside there, we can pass in a function and it has a request, a response object and a next() method.
Because there can be multiple middleware and also because this is something that happens in the middle,
the next function basically determines when we should move on from the middleware and continue in the
flow of the server handlers.
So when should it go to the next function that's in line?
So the middleware that we're putting inside the app.use() method can in fact be created from scratch.
And it's quite useful to see this, just to know roughly what's actually going behind the scenes with
all of these different modules that we're putting in here, like body-parser and
morgan.
So in this case, all I've got is a function that takes a request, a response object, and also has
a next() method.
Now when the middleware is activated, in this case, all I'm doing is just doing some logging, so I'm
saying log request method and then tap into the req.method property in order to print it out.
Finally, we have the next() function, which basically just says, okay, I'm done with all of my middleware
functionality, proceed to the next step of handling that request.
Now if there is another middleware here,
then that is where that next() is going to go to.
It's going to go to the next app.use, which is why it's really important in Express the order that
you put your middleware.
If you want your request to be authenticated before you log the request or before you parse the request,
then you have to think about the order that it's going in in your code file.
But once it's done with all the middleware, then the next function will actually go to your request
handlers such as our app.get or our app.post.
So what I want you to do is to take a look at this particular slide and think about how you can implement
it in your own code.
Now in this case, all I'm doing is just logging the req.method, but I want you to log the
req.method, but also the URL of the request and you can get access to these through req.method, but
also req.url.
Open up index3.js, modify the code here so that you can create your own logging middleware and
as an extra challenge, I don't want you to have the middleware like what we had in the example, which
is where we've got the function inside app.use(), I want you to make it look like the other middleware
that we've used.
Remember with body-parser, all we did was app.use() and then we just said body-parser, blah blah blah
blah, blah.
And with morgan it was again going into here.
So what your app.use() should look like is it should look like this, making sure that this line of code
actually works.
I want you to write the middleware function that's going to log the request URL and the request method
into the console.
Pause the video and complete this challenge.
All right.
So we know that we need to create a middleware function called logger in order for this line of code
to work.
So let's do that now.
It's going to have the (req, next), and then we're going to console.log() a bunch of things.
Now, how you format your console.log() is totally up to you, but I'm going to say "Request method" and
then afterwards is going to come the "req.method" property,
and then I'm also going to console.log() the "req.url" and I'll change that here as well.
And then finally, we're going to need the next() function to say that this function should continue on
to the next thing.
So let's go ahead and stop our server.
Let's use our Nodemon to run index3.js and now let's make some requests.
So let's make a GET request.
You can see the Request Method and the Request URL.
Let's try our POST method, you can see the Request Method and the URL.
So we've actually replicated some of the functionality of morgan by creating this middleware ourselves
and then using the app.use() method, we're able to specify the middleware that we want to be implemented
before we end up in the route handlers.
Now remember what I said about the next() method,
it's really common that people forget to use it in the middleware and this is what would happen if you
did that.
So let's make a Send request.
You can see it's just hanging, right?
Even though we've got all of these things that we wanted, console logged, logged,
but if we actually try to go to our home page localhost, then it's actually not going to load because
it never manages to reach this handler because right here we need that method to happen before we can
actually hit up that handler that sends back whatever it is that we need to the client.
So the order of things really becomes very clear when you omit or when you add in that next function
in the middleware.
All that's left to do now is to complete the coding exercise for this lesson and to prove that you've
learned all the things that we talked about, which is a lot in this lesson.
So putting all of your knowledge together, we're going to create the Bandname Generator. Again, going
back to your 3.4 Middleware, you can see that inside index4.js,
we've got everything set up for you to get started.
It's just a simple Express Node Server, but what you're going to have to do is to go ahead and install
the right packages, to import the right modules and then to be able to serve up the index.html website
when a GET request is made to our server.
So we did that when we did index1.js, remember? Earlier? And you can review the code from over there
and you can even copy and paste the code in because my stance on copy and pasting code is you're never
going to be able to memorize word for word what a lot of these methods and things are going to look
like, and it's perfectly acceptable to copy and paste code.
But, but this is a huge but, you have to understand what the code that you copied does, what is its
function, and not just blindly copy and paste code from the internet. But we've already gone through
it, so you should be able to review index1.js, add in the part of code that are required in order
to serve up the website, and also you should be able to get the middleware working so that we can actually
parse the information that's coming in from the form in our Bandname Generator. The Street name and
the Pet name, so that when the submit button is pressed and a POST request comes over to our server,
we know how to handle it.
And then finally, what we're going to do is we're going to do a res.send to send back the result of
the combined word.
So the first part is the Street name and the second part is their Pet name.
If you go ahead and use Nodemon to run the solution4.js, then if you go over to our localhost
you can see how it should function.
So let's put in my values here into the two inputs, click submit, and then we get back a h1 and a
h2.
And this is just an emoji which you can even copy and paste into your code if you wish.
And then this is the combined value of those two inputs that I put in just now.
So if I change this to Angela and then hit submit, you can see this is reacting to my HTML form.
So that's the goal.
Pause the video and give this challenge a go.
Now, this combines a lot of stuff that we did today.
And what I want you to do if you got stuck, is to take a look at solution4.js, the solution code
for the exercise and see where you might have gone wrong.
The first thing we need to do is to add our route handlers.
We have an app.get() on our root route that is going to send the file, which is our index.html inside
the public folder.
Remember to do that, we need the full-file path and to get the full path path we need this directory
name constant.
So you can simply have copied these three lines from index1 and that is going to get you that directory
name which you can append to the rest of the path, which is the public folder index.html.
And then once you've done that, the next part is to actually test it out and make sure that when you
go to your localhost:3000, you actually see that file being served up using the Send file.
So always break down a complex task into smaller tasks and test frequently.
Now, once that's up and running, then we need to install and get the body-parser middleware to work.
We'll import body-parser from the body-parser module, and then we're going to use the app.use() to be able
to parse urlencoded data.
And this again, you could have simply just copied over from the solution1.
This is something that we already did before and because you now know what it does, you don't have
to memorize it letter by letter and make typos and struggle in that kind of way.
This is something that you can simply keep save on your computer and refer to it whenever you need this
functionality because now you understand what it does.
Once we have that middleware in place, then we can go ahead and process the request body that we're
getting through the HTML form.
In my case, I created my own middleware called bandNameGenerator,
so another preprocessor that's going into our server.
So once we've parsed the information, then we generate the band name,
this function basically takes the request, takes the first part, which is the Street, and then adds
it to the Pet name and then hits up the next() part of our server.
And this app.use() is where this function is called.
So this is the first middleware that happens.
We parse the information, then we generate the name from the req.body that the user entered, and
then our server determines which route needs to be hit up.
If it was a POST request that came in to the submit route, then we're going to res.send() the actual band
name back to the user, h1 and a h2.
And that is how we end up with this website.
If you didn't create a separate middleware and you simply put this inside the POST route, that's also
perfectly fine.
It really doesn't matter.
I just wanted to demonstrate to you one potential option.
You could have simply put all of this in here and then just paste it like this.
This is in fact less lines of code, but it's always good to know other options, right?
And plus, I get to demonstrate to you what happens if we actually change the order of our middleware.
So if by accident I put my body-parser middleware below my bandGenerator middleware, then this is
what's going to happen when I go to my website.
So let's put in our Street name, let's put in our Pet name, hit submit.
We get errors, can't read properties of undefined.
Why is it undefined?
Well, it's because we're trying to access the req.body here, which is the first middleware.
But req.body doesn't exist yet because we haven't parsed the incoming request.
Remember, middleware order matters a huge deal and I just wanted to be able to demonstrate that to
you.
Hopefully, the rest of the code is pretty clear and you managed to get your version of bandNameGenerator
to work.
Once you're ready, head over to the next lesson where we've got the final programming challenge for
this section.
So I'll see you there.