This course has been updated! We now recommend you take the API Design in Node.js, v4 course.
Transcript from the "Exercise 1 Solution" Lesson
>> Speaker 1: I gave everybody a little note before I handed it out to you, and I 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 asynchronous programming. But you probably would have found out soon enough that you didn't really even need it.
[00:00:20] Because res.sendFile takes care of that. Especially if you looked at the next experience and saw that 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.
[00:00:33] If you went to the index page and started downloading. It's because that's the fs.readFile is putting in that content in 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 kinda confuse you a little bit.
[00:00:54] Because it's gonna help you learn. So you didn't really need it res.sendFile, reads the file internally anyway. So let's just go ahead and check out the solution, and I'll show you what I'm talking about. So I'm doing res.sendFile and I'm using __dirname. This is two underscores here, sublime just makes it look like they're one.
[00:01:15] There's two underscores. And like I was saying before in the earlier talk, all your files in node are wraps or something like this, so this is where we get these [INAUDIBLE], everything is wrapped inside of this.
>> Speaker 1: It's wrapped inside like this and we get access to like module, exports, __dirname, console, all that stuff, that's all we're able to do because call __dirname, because it's given to us at execution time by node, every file.
[00:01:52] So dirname is just a current directory name, which is in this case, whatever the name of your directory is. In mine it's node-api. So whatever the name of your directory, it's gonna be the current directory name of the current file that you are in. So by doing that, the res.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 wanna send.
[00:02:16] So I just put __dirname +/index.html. You can also use the path module to resolve that safely. So they deal with the trailing and leading slashes and get 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.
[00:02:34] But you don't have to if you don't really care. If you just wanna do that, you can do it. But checking for errors is okay if you wanna do something different. Here, I just wanted to show you an example of how you can set the status code of a response, and also send something back.
[00:02:49] It's probably not the best thing you wanna do on a request to an HTML page, but it's just an example of how you would set the status. So this is me saying, hey, I want the status code to be 500, and I wanna send back this error. Again, you'd probably never do this on a GIT request to the route of your application, but that's an example of how you would do it.
[00:03:10] Any questions on this part?
>> Speaker 1: So internally the res.sendFile is doing the fs.readFile.
>> Speaker 1: I just wanted you guys to see how that works. See what that feels like.
>> Speaker 2: Do you have a solution using fs.readFile?
>> Speaker 1: I don't, but we could do it right now, if that would be helpful.
[00:03:38] Would that be helpful? Anybody else? So what you would do is you would say, var, let's just say, first thing you need to do is require the file system module and we just do that by fs because it's internal. And then, I'm just gonna comment this stuff out.
>> Speaker 1: And then, what we can do is we can say, fs.readFile, is it capital case? Yeah, it's capital case. So we do readFile, we could also do readFileSync which would do it synchronously if you looked it up but, let's just do the asynchronous one and then that takes the path to the file, which is.
[00:04:25] Next, HTML takes in a callback. This callback is a node style callback 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.
[00:04:46] So in this case, the file buffer. So let's just do this, I'll show you what this looks like. So for console.log(buffer) on that and then if I start the server.
>> Speaker 1: And then, I do a Git request to that page. This is gonna 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.
[00:05:13] But if you go to the terminal, so there's the file buffer, that's the index the HTML. It's not really what we want so we need to convert it, so we'll just say var html = buffer.toString, that'll convert it back to the actual content by default it's gonna do utf8 encoding, so that's the HTML, and then you can say rest.
[00:05:45] Actually need to set the headers rest., what's the method for that, I can't think of the method to set the headers. We'll see in a minute. So rest.send and we can just say (html)-
>> Speaker 2: Set header.
>> Speaker 1: There we go. Set header, thank you. Set header. And we need to set the content type
>> Speaker 1: To text/html.
>> Speaker 1: So now if we do that, let me restart the server.
>> Speaker 1: We get the HTML.
>> Speaker 2: Does that implementation stream in terms of the HTML file?
>> Speaker 1: Could you string the content of the HTML file?
>> Speaker 2: Does this differ from creating a read stream from the file?
>> Speaker 1: Yeah.
>> Speaker 2: I can get to the response?
>> Speaker 1: Yeah, this is different. So good question. His question was is this different from creating a stream? This is totally different. So this callback isn't gonna be fired until the entire contents of the file is loaded or as a stream sends events as each bit comes through.
[00:07:02] So it's different. So it's gonna hold it in memory until it comes back. So a little different. And then, as far as like the other thing, getting the data, it was as simple as just saying, hey, if I go to Sly's data res.json the data, that's it, that's all we have to do.
[00:07:21] And then, of course, listen on a port. app.listen takes a callback 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 3,000. Otherwise it just looks kinda weird when you don't log something.
[00:07:36] Like if I just stop this and I just run the server, I don't know what's going on right there, there's just nothing happening. So it's a convention, what I do is always just log something.
>> Speaker 1: Any questions on this stuff? Yes?
>> Speaker 2: There was a question, they kinda were discussing in chat, but what's the best way to handle errors on your routes?
>> Speaker 1: We'll get to that. Good question, good, good question. The short answer is middlewares. Middlewares uses the answer for all this stuff, so [LAUGH] great question. Cool. So before we go on, I just wanna 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 tools we can use.
[00:08:22] And go on a deeper understanding of some of this 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 experience with node, or you don't know what this is.
[00:08:35] What we can do to get around that is we can MPM install. You can do i for short. And then -g for globally. nodemon, like that. And it's just like node, except for it's gonna restart our server when we make changes to the file, so if you don't have that globally installed, I highly recommend it.
[00:08:56] So what that would do is allow us to come in here and say nodemon and then, just like we would do with nodes 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.
[00:09:12] It won't restart the browser, you've 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.
>> Speaker 2: And what was the install command again?
>> Speaker 1: The install for that is-
>> Speaker 2: npmi
>> Speaker 1: npm, where'd it go? I'll do it again, I never executed that's why. It's npm i -g, for global, nodemon, M-O-N.
>> Speaker 1: Great and I just wanna also come back to this callback syntax here. When we get into the data modeling with Mongoose and stuff, we're gonna see a lot of this.
[00:10:00] So I just want you to get really comfortable. If you don't really have a good level of comfortability or callbacks, you definitely will after this workshop. So get used to callbacks, we'll switch over to something called promises but in node in general because it's asynchronous this event, it has an event loop, everything is gonna be in this pattern.
[00:10:23] So most of the stuff in node follows this error constant pattern where error is the optional first name. So most time in node you'll always see this on the first line of a function, if(err) do this. You'll see that almost every time. So get used to these patterns.
[00:10:40] And as you're developing stuff and note, you should follow the pattern too, so people know what's expected.