Transcript from the "Create a Server API with Express" Lesson
>> We left off creating this manual low level server which is, yeah, pretty good, pretty impressive, I like it. But you're not gonna ship this to production. So what you wanna do instead is use this amazing tool, probably one of my most favorite packages in the whole npm ecosystem, a whole node ecosystem, it's called express.
[00:00:24] It's such a fitting name because you literally can create a server super fast, like you're on the expressway. So the way we're going to use this is we're going to npm install express followed by these two other packages. So let's talk about these for a little bit. Express is a framework for building servers, short and sweet.
[00:00:43] Body-parser is a middleware that parses incoming requests, and morgan is a middleware for logging incoming requests. So what is this word middleware? Well, middleware is basically, if you think of a request coming in on a server, let's look at this. So requests coming in on the server, here it is, that means this callback is gonna be called every single time a request comes in.
[00:01:09] You can think of middleware as like a little piece of functionality that sits in between what you eventually wanna do with the request and when it came in. It's like a pipe of plugins that can manipulate the request, it can inspect the request, it can do whatever it wants to the request before it eventually sends it to another middleware or, in this case the controller.
[00:01:32] It's like you have a sandwich, one side of the bread would be the client, the other side of the bread would, no, one side of the bread would be the incoming request and other side of bread would be the response. And then somewhere in the middle is the middleware.
[00:01:46] Like all the stuff that's in the middle, and then the piece of meat is the controller, right? So the middleware is like all the toppings that just adds all the extra stuff to whatever meat or veggie patty you got going on there, that's middleware. So body-parser and morgan are those two.
[00:02:18] It's great for debugging, it's great for recognizing if and when someone requested you. You should never go to production without having some type of request logging mechanism. Because one of the most common debugging things you have to do as a back end engineer or a full stack engineer is looking at the logs to see when or what or how something happened.
[00:02:36] And if you're not logging, you're not winning, I don't know, you need to be logging, so we're gonna log here. So let's get started, we're gonna make like a simple little todos API that creates todos and sends the todos back, very simple. So like always I have the code here, you can copy and paste, but you can also just follow along with me if you would like to.
[00:02:58] So we're gonna do just that. So I'm just gonna keep this one here because why not? Let's make another file, and I'm gonna call this one server.mjs, and I'll add it to our server file. And we need to do some installations, so we're going to stop the server, we're gonna npm install express morgan And body-parser like that, oops, I wanna save that.
[00:03:31] So I stopped the install by hitting Ctrl + C, and then I came back and ran it again and saved it. So we got that, looking good, looking good. And so I just noticed I clicked on this node modules folder and you'll see that there's a .bin folder here.
[00:03:46] That means that there's something that I installed from node or from npm that has like a cli shipped with it, and if I go look at it looks like there's a mime cli. But I didn't install mime, I'm guessing express did or one of the tools that express uses has a cli associated with it.
[00:04:03] Because that means this package somewhere, whatever is creating this mime thing has a bin property on it's package.json whose key is called mime, that's why that's there. So this is what it looks like when your cli gets installed on someone's machine, it looks like this, it gets added to a .bin folder with the name of that field that you put on bin.
[00:04:24] So that's why that's important and it happens during installation of npm, when npm installs your package. Anyway, let's go back to our server and let's import express from express and we'll import What was it? Yeah, body-parser, was called a bp from body-parser and then imports morgan from morgan, so we got all of those.
[00:04:51] Now, with express, we need to create an app, so we'll say app = express, like that, so now we have our app. And then we want to go ahead and set up our middleware first, and then followed by our routes, and then lastly, we will open the server, we'll listen and we'll be good to go.
[00:05:08] So let's set up our middleware. So the way we can do that is we can say app.use, that's a method, and we can parse in an array of middleware, we can parse in one middleware, we can make one in mime right here with an anonymous function. We're gonna use body-parser, I'm gonna say bp, and I'll actually want to use something called URL encoded and I'll parse in an option that says extended true.
[00:05:35] Basically what this is going to give us is if someone parses some data on a query string, it's gonna parse that for us and it basically just make sure that we can parse the query string and whatever is in the URL pretty easily. We probably won't be using this in this example, but it's useful, and then the other one we want to do is app.use bp.json, this one we will be using.
[00:05:59] This one allows us to parse the json body of a POST requests, so we can actually see it as json and not like bits of chunks that we have to add together like we did in the http server. And the last one we want to do is morgan.
[00:06:16] So we'll say morgan and will parse in dev, is just the type of logging that you want, I think there's different options here. Let's see, so you can parse in, there's like different formats you could do, we're just gonna parse in dev here, maybe if I take this away, it'll show me, let's see.
[00:06:37] Yeah, there's combined some other options, I always just use dev, cuz it's the shortest one, it's giving me the simplest amount of information. So now that we got our middleware, we need to set up some routes. Before we do that, let's create a little database so we can store our todos.
[00:06:51] So I'm gonna say db = an array, and now we're gonna set up some routes. So I wanna route to where if I POST to slash todos, it'll create a new todo and add it to the database and then send that back. And if I do a get request to slash todos, it will just send me back all the todos.
[00:07:08] So I'm gonna say app dot followed by the verb that I want, so in this case I want to do the POST. So app.post, that's a method, first argument is going to be the path that I want to receive. I said I want todos, so I'm gonna say todos, and then I'm gonna say todo actually, keep it singular.
[00:07:30] And then whatever controller you can think of it as like, what callback do you want to run when someone does this POST requests, okay? And just like the http server because guess what, express uses the HTTP server underneath it, we get this request and response objects. And you'll see this pretty much in every single node js server implementation, whether it's express or happy, or whatever server framework you use.
[00:07:54] They pretty much all use request response best cuz they're all using the http module which uses request and response, so it's very common to see this pattern. So we're going to say, okay, cool, we want to first grab this todo and add it to the database, so let's do that.
[00:08:12] So we'll say new todo and that's gonna equal an object, we'll just say the ideas, I don't know, Date.now, so I don't like incremented IDs, and then the text is gonna be whatever is on the request.body.txt. So that means someone's gonna POST an object to this server and that object is gonna have a text property on it, and the value of that text property is gonna be whatever is gonna be saved here and that is todo, and that's it.
[00:08:40] So now we got to need todo and I'm gonna say db.push are new ToDo here like that, and I'm gonna say res.json newToDo. And that's simple I was able to create it ToDo, push it in our database and then respond back really simply. So we're gonna do the same thing before get requests, so I'm gonna say app.get/to do.
[00:09:05] Remember, a route is a combination of a verb and a path, the verb here is a POST, the path is todo, the verb pairs get, but the path is also todo. So although they both the same routes, they're different paths cuz it says a get verb associated with it.
[00:09:19] So it's gonna only be activated when someone does a get request to this route or to this path. So request to response And then, for a get request, all you wanna do is just say res.json(db). Let's just show all the todos, that's pretty much it. And the next thing is we want to start our server so we can listen on it, so we'll say app.listen, looks familiar, right?
[00:09:49] If we go back to here, is that what we did here, server.listen? It's really, like I said an abstraction around http module, which already does this. So we'll say app.listen, we don't have to parse in a host here, it'll default to localhost for us or whatever host you're on, and we just need to give it a port.
[00:10:05] So I'm gonna just give it the same port 8000, and it does take a callback optionally. If you want to use that and we'll just pretty much do the same thing, console.log server on http localhost 8000. So we'll do that, and that's gonna be our server. So let's give it a try and see what happens.
[00:10:31] So, we will come here, we will run server in js, and you can see we still get the same output server on http localhost 8000. So first I'm gonna do a get request to 8000. No other route, no slash todo, just a get request and I should get a, cannot get, I get a 404 not found.
[00:10:58] Why is that? Pretty sure we just created a server, it seems like it's working, so why is it saying it isn't found? Well, it's because I didn't register for a route of the verb get in the path slash, so it just 404. So if I want to get rid of that I would make a route for app.get/ and I would handle that.
[00:11:20] Or I could do like a catch all somewhere down here that says, if someone tries to make a request to anything that's not the stuff that I just put above here, then show that. And that's how you can handle errors without your app crashing and stuff like that with express.
[00:11:33] So there's many ways to do that, it depends on whatever logic you want, but that's why that's there. So that's actually a good sign that we see that because that's what we intend to happen cuz we don't have a route registered for that path and verb combination. So what we'll do, is we will actually hit one that works, let's do a POST request.
[00:11:49] I'm gonna start the server again, I'm gonna use my http pi and I'm gonna do a POST request to /todo, and I'm going to post the text property. So this text says I need to eat more food today, I don't eat enough, I should eat more than I actually I'm, I got to be too busy, I don't know.
[00:12:13] So, we'll do that, and you can see, I get a 200 and it sends back this json objects, says here's the ID which I put date.now and then our text. So I'm gonna add some more Clean up my closet. I just drop my clothes at the bottom of the closet sometime so I need to clean it up, there we go.
[00:12:34] So we got two todos now, the server is still running, if you look at these nice little pretty logs we have, this is morgan. This is that middleware that's logging this for us. You can see we got one request coming in it was a POST /todo status code 200 and it took 3.60 milliseconds to function.
[00:12:53] I have no idea what this number is with morgan but I'm guessing some time or something, and then the other one took even less. So super fast, as you can see, this is just a local machine doing really good here. Now let's actually see if we can pull those todos down with the get request.
[00:13:12] Before we do it, the server hasn't stopped, it's been running this whole time. And I was putting those todos to an array, so that means I'm anticipating that because this server is still running, and because I pushed them to an array, that those objects should still be floating in memory right now.
[00:13:29] It should still be sitting around waiting for me to pull them down. And that would only happen if the server was still running, it didn't stop like our other node programs did. So let's prove that theory, and let's do a get request to /todo. And you can see here we get an array of both of the todos that we have.
[00:13:48] Because we're still running the server, they're still in memory and everything still works, and you can see we do get a get to /todo 200, good to go. I think this number is like how much data was sent back, that makes more sense. So maybe that's what that is.
[00:14:03] I am going to stop the server and start it again, and then I'm going to do that, you'll see that nothing comes back because I stopped the server and there was no data in memory. Yeah, so as you can see, let's just kind of compare apples to apples here.
[00:14:18] So I'm gonna try to, I forgot the shortcut to open this up in a new thing, it's like Command + K, I don't know the shortcut anymore, how do we do this? There we go, split right, here we go. So let's close this, I think this is like Command + B, okay, so we got the server here, which is an express and then we got the http server, which is just regular old http.
[00:14:44] So, if you look at the amount of code, it's about the same to be honest. But in my opinion, this is just a lot easier to understand, a lot more expressive, and it's actually doing more. So although there's about the same amount of code, this is way more efficient, it's doing a lot more.
[00:15:01] We need to be registering the routes up here, we just had like a handler for a POST and that was it. This thing has a database, a couple of routes, it's doing a lot more with the same amount of code. So as you can see, it can get pretty crazy, if you take advantage of something like express versus trying to build this out yourself.
[00:15:18] It would be a lot more code to get the same functionality. Any questions on express and the plugin, the middleware that I added here to get this work? The question was, can we customize the response codes in the express controllers, and the answer is, of course you can.
[00:15:35] So the POST we can say res.set header, which is pretty much the same thing, but I think the one we want is status. So if you say rest.status, I can say 201, save that, stop this, start that, and let's do another POST here, and you can see I got a 201, right?
[00:15:57] So yeah, you get the res.status to change it. I think you can also do like, you can change this, you can see like res.status.json, and then just do that. I think that works too, we're about to find out. Yeah, that works too.