Scott walks through the solution to exercise 1. He also shares a few workflow tips, like using nodemon to automatically restart the server after each change.
(flute music) - I gave everybody a little note before, I handed it out to you and was like, look at the file system module. The reason I told you that is so, I wanted you to struggle a little bit with asingers programming, but you probably would've found out soon enough that you didn't even really need it, because res dot send file takes care of that. Especially if you looked at the next branch and saw the solution. So, you didn't really need the file system, but you could've used it, if you did do it, you'd have to set the appropriate headers to get it to work, otherwise it would start downloading the file, if you went to the next page and started downloading.
That's because the res dot send file is putting in that content into res dot, I'm sorry, fs dot refile is putting that content into there. So, you didn't really need it, but I wanted you guys to see how asynchronous stuff works and that was a good way I could sneak it in there, and also kind of confuse you a little bit, because it's going to help you learn. Also, you didn't really need it. Res dot send file reads the file internally anyway, so let's just go ahead and check out the solution, then I'll show you what I'm talking about.
So, I'm doing res dot sendfile and I'm using underscore underscore dirname. This is two underscores here. Submlime just makes them look like they're one, but it's two underscores. And like I was saying before in an earlier talk, all your files and node are wrapped in something like this. So, this is where we get these globals. Everything is wrapped inside of this. Oops. So, wrapped inside of it, it'd be like this. And we get access to module, exports, dirname, console, all that stuff.
That's how we're able to do, we can just call dirname, because it's given to us at execution time by node, every file. So, dirname is just a current directory name, which is in this case, it's going to be whatever the name of your directory is. In mine, it's node dash api. So, whatever the name of your directory, it's going to be the current directory name of the current file that you're in. So, by doing that, res dot sendfile, if you looked at the documents for it, which I'm sure most of you did, you notice that it needs to take a absolute path to the file that you want to send.
So, I just put dirname plus slash index HTML. You can also use the path module, to resolve that safely, instead of deal with the trailing and leading slashes, and getting messed up there. And because it is asynchronous, we have the option of putting this call back here to check for errors and do stuff, but you don't have to if you don't really care. If you just want to do that, you can do it, but checking for errors is okay if you want to do something different. Here, I just want to show you an example of how you can set the status code of a response, and also send something back.
It's probably not the best thing you want to do when you send on a request to a index to HTML page, but it's just an example of how you would set that status. So, this is me saying, hey, I want the status code to be 500, and I want to send back this error. Again, you'd probably never do this on a get request to the root of your application, but that's an example of how you would do it. Any questions on this part? So, internally, res dot sendfile is doing the fs dot refile.
I just wanted you guys to see how that works, and see what that feels like. - [Male] Do you have a solution using fs dot refile? - I don't, but I can, we can do it right now, if that would be helpful. Would that be helpful? Anybody else? Okay, so what you would do is you would say, var, let's just say, oops. First thing we need to do is require the file system module, and we just do that by fs, because it's internal, right? And then, I'm just going to comment this stuff out.
And then what we can do is we can say, fs dot readfile, is it CamelCase? Yeah it's CamelCase. So, we could do readfile. We can also do readfileSync, which will do it synchronously if you looked it up, but let's just do the asynchronous one, and then that takes in a path to the file, which is index HTML, takes in a call back. This call back is a node style call back, and when I mean node style call back, usually the error is an optional argument that we passed in if an error occurred while this function was executing, and then a second argument is usually the content that you're asking for, so in this case, the file buffer.
Alright. So, let's just do this, I'll show you what this looks like. So, if you console dot log, buffer, on that, and then if I start the server, and then I do a get request to that page, it's just going to hang. As you can see, it's just spinning right here, because I didn't send a response back to the client, so it's just hanging, but if we go look at the terminal we should see that buffer. So, there's the file buffer. That's the index dot HTML. It's not really what we want, so we needed to convert it, so we'll just say, var dot, or var HTML equals buffer dot toString.
That'll convert it back to the actual content. By default it's going to do UTF8 in coding. So, that's the HTML. And then we can say res dot, actually, you need to set the headers, res dot, oh, what's the method for that? I can't think of the method to set the headers. We'll see in a minute. So, res dot send, and we could just say HTML.
- [Male] Subheader. - Oh, there we go, subheader, thank you. Start, set, header, and we need to set the content type to text slash HTML. So, now if we do that, let me restart the server, we get the HTML.
- [Male] Does that implementation stream the contents of the issue on file? - Could you stream the contents of an HTML file? - [Male] Well, is it, does this differ from creating our restreaming file and typing it to the response? - Yeah, yeah this is different, so, good question. His question was, is this different than creating a stream? This is totally different. So, this call back isn't going to be fired until the entire contents of the file is loaded, whereas a stream sends events as each bit comes through, right, so yeah it's different.
Yeah so, it's going to hold it in memory until it comes back, so yeah, little different. Okay, and then as far as like the other thing, getting the data, it was as simple as just saying hey, if I go to slash data, res dot json the data, that's it. That's all we had to do. And then, of course, listen on a port. App dot listen takes a call back function that you can just do something inside of it, so that's why like, when I start the server, you see this on mine, listening on port 3000. Otherwise, it just looks kind of weird when you don't log something.
Like, if I just stop this, and I just run the server, like I don't know what's going on, right there. It's just nothing happening, so it's a convention. At least what I do, is I always just log something. Cool, any questions on this stuff? Yes. - [Male] There was a question they kind of were discussing in chat, but what's the best way to handle errors on your routes? - We'll get to that, good question, good, good question. The short answer is middlewares. Middleware is usually the answer for all the stuff, so Great question.
Cool, so, before we go on, I just want to walk through some of the things that we did during the solution, and talk about some things we can do to make it better, and like tools we can use, and go into deeper understanding on some of the stuff. So, one thing we might have noticed is that every time I made the change to the server, I had to stop the server and start it again. It's kind of annoying, so if you don't have any experience with node, or you don't know what this is, what we can do to get around that, is you can npm install. You can do I for short, and then dash g for globally.
Nodemon, like that, and that's, it's just like node, except for it's going to restart our server when we save, when we make changes to the file. So, if you don't have that globally installed, I highly recommend it. So, what that would do is allow us to come in and say nodemon, and then just like we'd do with node, server js and then run it. You get all this other output and stuff, but then now what happens is, when I just come in here and just hit save on the file, it'll restart the server. It won't restart the browser.
You still got to refresh the browser, but it will restart the server. So, this is a good one. This is what we're going to be using from here on out. - [Male] And what was the install command again? - The install for that is-- - [Male] Npm I. - Npm, oh where'd it go? Did I pass it? Oh, I'll do it again, I never executed it, that's why. It's npm install dash g for global, nodemon, M-O-N. - [Male] Thanks. - Mmhmm.
Great, and I just want to also come back to this call back syntax here. When we get into the data modeling with Mongoose and stuff, we're going to see a lot of this. So, I just want you to get really comfortable. If you don't really have like a good level of comfortability with call backs, you definitely will after this workshop. So, get used to call backs. We'll switch over to something called Promises, but in node in general, because it's asynchronous, its event, it has an event loop, everything is going to be in this pattern. So, most of the stuff in node follows this, you know, error, content pattern, where error is the optional first thing.
So, most of the time you know you'll always see this like on the first line of a function. If error, do this. You'll see that like almost every time, so get used to these patterns. And as you're developing stuff in node, you should follow the pattern too, so people know what to expect.
This course was created by Frontend Masters. It was originally released on 12/30/2015. We're pleased to host this training in our library.
- Executing Node.js
- Using Express
- What is middleware?
- Testing in Node.js
- Using Mongo with Node.js
- Data modeling
- Querying data with Mongoose
- Identifying sensitive routes
- Configuring the deployment