Loading
Lesson 54
Courses / Software School
Creating an HTTP web server with Express.js - Software School (2024-06-04)

In this lecture we learn to create an HTTP web server in the Node.js (Serverside JavaScript) programming language. We use the library Express.js that is downloaded from the NPM registry.

We start off creating a directory for the project and generating a package.json file. Then we install the dependencies necessary for Express.

We quickly power up an HTTP server by issuing a command on the Terminal. We learn to handle the root slash endpoint. You can call on the Express app with the HTTP method as the function to be called. Two arguments are needed: first the path to the route and the second the route handler function, which in turn takes two parameters: the Request and Response objects, respectively.

We learn to send back a text response. Then we proceed to send some HTML text. Later we create an HTML file and learn to read that and serve as the response.

The lecture also teaches you to use a middleware to serve static resources such as files that end in the html extension. A middleware is placed between the request and response pipeline to do some processing. Anyone can create a middleware function by defining with the signature of three params: req, res, and next. The next function is used to move the pipeline forward.

In particular we use the Express Static middleware to serve HTML pages from the public directory.

The lecture mentions how you can change response headers and the status code.

In the end we learn how we can send a JSON response back to the client. There are brief comments about how traditional web development morphed into separate frontend and backend, the primary method of communication today being through HTTP, using the JSON format.

Video Transcript

Today, I'll talk about Express.js. Express.js is a library that you can install in the Node.js ecosystem that is JavaScript server side. So this is the website. If you want to know more about it, express.js.com. Now, of course, you're going to need Node.js NPM, the Node package manager, so we can install Express. Here's a website, Node.js.org. So make sure you have that. And yeah, so just give an overview of why Express. Well, so when you have a website, we have an application today, you go on a browser, you receive a web page back, right? You have a HTML document of some CSS, some JavaScript. That is served by a server. There's something that's giving you back all that stuff. So Express.js is a way for us to build that kind of server. It's called an HTTP server. You know how you communicate in the browser usually through HTTP, hypertext transfer protocol. And then we make a request for a resource and we get back a response. Express makes it very easy for us to create that server. Of course, we could have used the server side of JavaScript Node.js and wrote everything from scratch using the HTTP module, but that's not very convenient. So what we do is we usually use a wrapper or abstraction on top of the built-in modules. And one of them is Express. Of course, there are other ones like popular today, I don't know, Nest, JS might be a choice. But Express probably the most straightforward way and historically is very popular. And it's very simple to do. So if you come from background to other programming languages, if you use Ruby, this is like the Sinatra of Node.js. All right, so let's get started. First, I need to go to a terminal and create a directory for my project. So I'm going to share my command prompt here. I'm using Windows right now. So I'm in a directory here. And I'm just going to create another one to host my project. So if I'm on the command line, I can do mkdir. This command works for any platform. And if you don't like doing command line, just go on your file explorer or find your Mac or whatever, and right click and new folder. Anyway, I'm going to call it introduction to Express, separated by a dash or lowercase. Now I'm going to change that directory of the command CD space, introduction to Express. That command is also the same in any platform, Windows Mac Linux. Okay, right now I don't have any files. So what I got to do is first initialize this as an NPM project, so that I can install packages from the NPM, the Node package manager registry. And to do that, we can use the NPM command. If you install Node.js on their website, you should already have the NPM command as well. Space init. So all this command will do is create a file called package.js. And it asks a few questions. If you want to answer them, it's up to you. I'll just press enter all the way. I can always change this later. Enter all the way and say yes, it's okay. And I'm going to open this directory in my text editor. That's visual studio code. So my command here is code space dot dot means the current directory. And all that get that NPM init command did was create the file package dot just Jason with the information that was filled in as we pressed enter. So let me share my visual studio code screen here. Of course, you can use any text editor or ID of your choice. Doesn't matter. Here's my window for a visual studio code. I see there's a file that was generated by NPM init package dot json. It's just a file with a format called json, JavaScript object notation. And we have like pretty much it's a property and value, property and value. And the value themselves can be strings or it can be as an object like this one. In any case, those are all the values that were input when we type NPM init. Now, if you'd like, you can I can go back to my term it to install X express as a dependency, or I can do it from my ID if I press control back tick. That's also an option. So I don't have to keep switching back and forth the shared screen with you. In any case, I have a PowerShell instance open here in my visual studio code. And you can do in your terminal, whatever it is. I'm going to do NPM space install space express. So this is the command to pull or download a third party code from the NPM registry. So express was written, the code is already written by somebody else. All we're doing is bringing that code to our project. So if you notice here in the file explorer bar, I have a node modules directory. That's where all the packages installed by NPM go. In this case, I'm going to look for express. See, this is the one that installed it downloaded that source code is now available here. So you can see the search code there. So that means we are leveraging the work of another person, right? We don't want to start from scratch. We don't want to reinvent the wheel. We're going to work with what somebody else already wrote. So we're going to leverage this code for the express library. In any case, that's how you know it's been installed. You've noticed there's also other directories. And that's because the express in turn, if you look at its package.json, it has a dependencies property that has a lot of other packages. So express by itself also depends on other people's work. Now let me collapse everything, go back to package.json for our own project, you're going to see express has been added to the object that's the value for the dependencies property here. And the right hand side means the version that was installed. Okay, so this means this parrot means any minor or patch version, minor meaning the middle number and patch the right hand side number. So that would be far point something points something, but it doesn't allow five because they'll be probably a major version changes we have breaking changes. So you don't want to have it automatically install it that way. Okay, so we got the express there. Finally, let's right click here, new file, I'm going to create a new file in the root of the project. I'll call it index.js, or you can call it server.js, whatever. So first, in Node.js, we're using Node.js here. So that means JavaScript server side. So if I want to pull or use a module that was installed by npm, I have to use require. And then parentheses, the name of the module being expressed. Now I can put this in the variable, I usually call the same name of the module. So I'll call it express. Now if you want a semicolon for JavaScript. And while I'm at that, I have my extensions enabled, I don't want that out of completion, because we're beginners here. So I'm going to disable that. While I'm doing that, one moment, disable that. There you go. Let me see if I disable this too. All right, going, going back to what we're doing. So we have the variable express. So we just call it as a function. And that will return what's called a usual application. And we usually call it a pp, the variable name to start at. And finally, you can define stuff or endpoints or routes and stuff, but I'm not going to do that right now. I just want to power up the server. To do that, I call the function that belongs to app called listen. And it requires us to say, Okay, I'm listening, what's the port. So I can put the part in a variable here const part. Let's usually 3000 is a very common one. And I can use the variable there. And if I do it this way, save it. And then in my terminal, I'm going to do to run this script. I say node space index.js. Now you notice nothing is happening, but it's actually running the server. I see it up if there's no prompt. So if I press Ctrl C, that sends the interrupt signal, that will stop. Okay, Ctrl C. Don't forget, you want to stop Ctrl C, send the interrupt. Anyway, that's not very user friendly or developer friendly. So we want to add a second argument to listen. And that's the function I can use your arrow function or the normal function. Doesn't matter. So this is a callback function that's called immediately after the service run. So we can say, Okay, let's do a console.log. And say like this, I'm going to use a back tick as I interpolate server is running. Wow, this is auto completely I don't want this. Because we're beginners, but whatever. So server is running on HTTP. Don't put s. That's a common problem. Local host is usually an eight is to 127, when 0.01 and colon the port, the port comes from the variable here. So I'm interpolating meaning I'm going to take the value from port and replace it here. So imagine this became like that. That's thanks to the back tick that I use here. If you use like single code, it doesn't work. You need to use the back tick. That's the character next to the on the tilde key. If it's also next to the keyboard number one. Anyway, on American keyboard. So we got that save it. Now let me put node index.js again and say service running on that address. What's nice about putting the HTTP address here is I can hold control and click to follow the link at least some visual studio code. And any terminal I think happens. So I'm going to open that in the browser. So let's do share the browser here. HTTP colon localhost 3000. And if you see it put localhost 3000 there with HTTP. I should see cannot get slash that means the server is actually running. If you don't see anything like something is broken or whatever cannot connect that means it's not running. The reason saying cannot get slash is because the server hasn't been programmed to understand your request to the slasher route and point. As how everybody doing so far. Let me know if you have trouble running the server. All right, so I'll go on here. See. Oops. One moment. Here's the back to visual studio code. Let's make it exciting and add an endpoint meaning. Okay, if I go to HP localhost 3000 slash I want to see a message. Hello. So hello world. To do that I just call the app object dot and I can use the HTTP method you remember HTTP. You need a method is it get is it post. And there are other ones but usually it's got a post. So I want to do a get. That's the method when we go on the browser and you type anything the address bar press enter. That's a get request to that endpoint. When I say endpoints like the URL address, whatever routes, whatever you want to call it. Okay, call it there's two arguments. The first is the path. Okay, we're going to be relative to this server is going to be slash meaning the root one. So when I go HTTP colon slash localhost colon 3000 slash slash being optional is going to go here. Now it's going to call this function. That's the second argument. And this function gets the arguments rec and res, the two one the first for the request the second for the response, you can call them whatever you want I usually call them req. And the other one are yes. Okay, now to reply something back. So when I hit slash right is going to call this function. And I need to give back a response because I'm being asked for something hey server, I need a resource I need something. Can you give me back the response so we do that through the response object or yes dot send. That's the most generic way of doing it. And you can send whatever if you want to don't want to send anything to reply anybody just send within any without any arguments. If you want to send a text put a string here and say hello world for example. Now this is going to be sent as plain text. It can use single double quotes doesn't matter. Or even back tick. Okay, now I made a change to my code here. But my server won't automatically adopt those changes. So we got to go here to terminal, press Ctrl C to interrupt and shut it down. And then restart it typing the same command again node index.js. Okay, now going back to the browser. If I refresh or go to the same route route I should see hello world. Let me increase the size of the font so you can see better. Okay, hello world's there. Now I want to press F12 to open DevTools. Now I'm using Firefox but it's usually the same in other browsers, premium based. Yeah, I'm going to the network tab because I want to monitor this request. Click that. I'm going to reload the page. I make sure the filters collected to all there. And I can see here this row is for the request to slash. And here's how I can see the details of this get request. I can see it's get because you see the get verb here. And then the address or URL, and the status code for this response was 200. Okay. And the version of HTTP was 1.1, and so on. So we also get what are called request headers, response headers in HTTP, request headers meaning something we send a metadata or additional information we sent to the server. These are all the pairs of property and value the property being the name of the header, and the value whatever. So you have a lot of metadata here. In any case, there's also the server replies with something and they also has headers. And one of them is interesting as x power by, which says express value. This means okay, the server sending back a response with some metadata in the header x power by to let us know the server is an express JS server. In any case, this is how you debug in a way at the response there. And you can even click this response tab, it shows you the actual if you click raw, is the raw response body, the text Hello World. And I think if I go back to headers, the response content type here is text. Oh, it's setting to text HTML. Interesting. Not plain text. It's probably expressed doing that by default. Okay, so content type is a header that says okay, we send you back something. And that something is of the type text x HTML, that's supposed to be an HTML page. And the care set is the character set we usually use UTF eight Unicode, the codification of the characters. Okay, I'm gonna close the DevTools. How everybody doing so far? Got Hello World was able to analyze the request and response DevTools. Okay, hope everybody's doing well. Let's go on. Going back to the code. Now this is nice. But if I want to have this route or endpoint that slash Hello Dash World instead of the root, well, I could just change the first argument to get here and say Hello Dash World. So when I go to local host slash 3000 slash Hello Dash World, they will go to this route. So if I go save that restart my server control C, and you shoot the same command again, if I refresh is not going to work, right? So it's gonna get slash because I changed the endpoint path. So now I have to say slash Hello Dash World, and it will hit the same Hello World. Okay, so you can have any custom path you want. Cool. Now, like I said, going back here, we can also send HTML here. So if you want to send some HTML page, you can say HTML tag here, then body, and Hello World in a paragraph. How about that? P tag there. Close the P tag, close the body, close the HTML. Now, usually, I explicitly like to add that I'm sending HTML to the user who requests this. So we can set the content of a header. Okay, if I just say res dot set, that's one way there's two ways a set or set header. If you just set, we can pass the name of the header content type. And then second arguments, okay, what's the value tax slash HTML. So this is setting a header. So you can set any HTTP header here by setting the first name being the first argument being the name of the header and the second value. And then make sure to do that before you issue the send command, because you cannot do it afterward. Okay, make sure before the send. Okay, let's save that and kill the server. Run it again. Let's see if that's working. Refresh. Like visually the same, but let me right click and view page source. I can see HTML here. See the tags are there. And if I close this, and open the dev tools with the F 12 where you can right click inspect, click on the inspector tab on Firefox or elements tab on chromium based to see the DOM, the document object model here, I can see there's HTML tag body and P hello world like we did. Okay, so you can make it should be server to send back HTML. Okay, let's go back. That's nice. How about we make another one. Let's say we do. So you can you can proceed to make any other endpoint by just calling app dot whatever app dot get app dot post, if you want to do a post, they could do app dot get slash another endpoint dash endpoint, add a second argument to the function with parameters rec and rest for request and response respectively. Oops, no arrow there. And then you can just do whatever do some processing if you need, and then send back a response, it's all going to boil down to you have to do res dot send. In the end, you got to send something back. Now this something could come to another place you can make a variable here start some value process, look up in the database. That's what we typically do like when we get a request for resource, we look up somewhere like a database to see if a resource exists, if it exists, I'll retrieve the information and send back to the user. Let's say we have some information. Laura Gibson here in a variable, I can send it back here by putting a variable there. And it should send it as well. Now I keep killing the server and restarting it. And go into the browser. Let's try slash another endpoint with a dash between I get Laura Gibson. That was the valuable value for the variable. Now that's, you can keep going like that and build as many routes as you want. Now, let's see, not the thing I want to show is okay, we don't have to hard code html here. Obviously, this is not how we do it. It's not the good way. So usually you can have a folder here if you create public folder, we can move this html from Hello World to a file called Hello dash bro.html. Let's do that. I'm going to take this content here, copy and paste to Hello World.html. If you want a format like that, they can do it. I did it with control shift P format document. That's a visual studio function. You can do that. Anyway, this is the content. It's in a file now. So how can we send content from a file? Well, we had to read the file first, and then send the content. Now to read it to Node.js, first we need to leverage the module FS. So require at the top FS under quotes, put in a variable as you call it the same name as the module FS. And then here before we send anything, we got to read the file. So to read a file, we're going to call FS.readfile. Now there's two, there's different ways to read a file. There's the synchronous version, there's the asynchronous and there's the promise version. FS promises.readfile is another way. I'll do the synchronous version for the sake of simplicity. Okay, so I don't have to deal promises. So okay, what's this, this function will read a file if you give the argument first being the okay, what's the path. Well, I'm just going to say public slash hello dash world HTML. Not going to care about like Windows path Linux path right now just and you know building path using the path module. Just do it like that. Okay, now second option I like to add always the encoding. I can pass an object with the encoding property being utf eight dash eight or eight doesn't matter. Same thing. Now reason I do always do this is so we don't forget because I've had problems when I worked in production for a company where it was not applying the encoding correctly when reading files that cause a lot of problems. So I was making sure to put in quoting when I write or read files to be utf eight explicitly. Okay, when we do this, it's going to return a string with the content of the file we can store that in a variable if you wish. Let me call the variable const file content. And then we can leverage that and use that to send here file content. As far as you got to put this already there that doesn't matter I can put in a variable as an intermediate step. Okay, so we're going to read the file, the file goes to the variable as a string and then finally send that string to the client, which is the browser. Now before I restart and do my thing again, let me just show you a way you can no longer have to keep shutting down the server for every change that you make in the source code. Now I can stop package called node mon. So it can do npm install. Now I'm going to do dash dash save dash dev node one. Like that. The reason I put dash dash save dash dev is so it's going to be installed under dev dependencies instead of dependencies impact dot jso in because usually don't want is not the server production when we run the app production we don't want to be restarting for every change. So don't use that in production is just for development. So node one is installed. And we can go here and say MPX node one index.js. Now the reason I use MPX is because it will look for node mon in a node modules dot bin node one here I'm using Windows so I should use CMD. So this is the command for node one. So if I don't want to use MPX, I would have to specify the whole path like dot slash no modules slash dot bin slash node one like that. And it will run node one. If I don't want to type the whole path just put MPX there and it will look for that in the node modules directory. Okay, this is nice, but usually people will add to the package json under scripts. You can add the start or dev or whatever you want to call it. Let me add start here. And let's call it node mon index. So yes, notice when I do scripts here I don't have to type MPX because it's already going to know that's going to take for no modules. So if I do this the reason I do that is for convenience so that instead of me typing MPX node mon index.js you can just type MPM start and it should start it like that. Now if you named your thing dev or something other than start you have to say MPM run, okay? MPM run whatever you said. Okay, start is just a special case. Okay, so now node wants taking care of listening for changes in the file so that means I can go here in my file, I can change something. Like maybe I'll say lauren ipsum whatever. Save it. Watch the terminal here says node mon is restarting due to changes. So it already restarted the server because it watched and noticed that you changed the content of the file. So that's what you want to use in development because it's very tedious to have to keep killing the server every time you make a change. Killing and restarting. How everybody do so far. Any question? Okay, that's the tooling and what we got here. Let's test it out. Going to the browser. If I refresh this you see whatever here. Yeah, whatever. Going back to hello world. You can see now hello world is here and that's coming from the file. Right if I go here and change the file and say hello world run file. Save the file, go back to the browser, refresh, I still see from file. Okay, that's a step forward now instead of us having the hard code the HTML but still not so very good because you know if I look here. Okay, what if I have so many pages right website today has thousands of pages where I'm not going to have going to make one endpoint for each like this. Imagine that 1000 page up to 1000 times do this. That's not good. So we don't want to do that. So what happens as if we were to write it from scratch we were just a programmatically read the file listing for the director public and generate code that looks like this for every single file that I find. Obviously we don't have to write that from scratch so we will leverage what's called a middleware for that and express static middleware so middleware is something that stands between the client making the request and your response. In the case of express say when I ask for hello world resource, it's going to go through the pipeline and express and eventually hits this function that returns the response. Now this pipeline we can inject something there. So we intercept and that's called a middleware. So every time you try to access something that might be from like the public directory will intercept the hey they're trying to read a static HTML file so we're going to reply with all this code that we generate like this read read the file and then set the content to HTML send it. Now to use the middleware all we have to do is say app dot use and then pass the middleware function here now middleware function is just like the handler function here that we typically use except we also use a third argument called next. That means whenever I'm done with the middleware processing I call next so that it goes and continues in the pipeline to eventually reach the response handler function. So here we're going to pass that function and that comes from express dot static and you got to call it like this so express dot static. You have to tell it the first argument okay what's the directory you want to listen for static files that's public. And then you can say here. Usually we want to add the. Options here additional options to this middleware one of them is extensions. And you can read the permission here this is so you don't have to type in the route when you say hello world dot HTML you don't have to say dot HTML can drop that extension so if you say extensions like. An array of a string HTML. That will make that happen. You see my my visual studio code gives some information about that here you can read your ID probably does that as well otherwise you can always reference the docs let me show you. Going to the browser go to express.com here the docs you can look at the API reference I'm using version for remember to pick the right version. And you can look at the reference here. It's probably somewhere there's express dot static seated on the left hand side express static and it tells you everything about that function and these extensions is here if you look. Set files extension fallbacks whatever. Okay in any case. Going back there to the visual studio code. So. Let's see. Let's see. Let's see here. So when I do that let me comment out or when I comment out code it means the program ignores that so I'm going to comment out the code for hello world here see if it's going to work coming from public with the middleware. Now remember node one already restart yep so I can go back here and see if hello world is working still after I press control R or command R and Mac to refresh or click this icon here. So it's still working. If I for some reason renamed the file let's test it out to see if it's really working. I'm going to try to break it go to public hello world going to rename it hello world to that HTML and let's see if it's really working now I says cannot get slash hello world see that. So it's working. So the middleware. Right when we do this call here all it's doing it's returning a function. Think of this thing whole thing here as returning a function that has rec resin next and inside this function is doing that processing and then calling next to go forward of the pipeline and that process is basically what we did here. Read the file. Okay we're trying to reach. It goes through this public directory it sees there's hello world to that HTML so I'm going to create an endpoint for that. And then I'm going to read this file content and send a response with the file content. So if I go to browser you put hello to it's working. Any questions so far. I'm going to revert back to hello world. Okay I'll go on. Now this is all nice but we're so far have only served static things. That's not how the real world. The most popular thing to do express is today modern apps. We typically send back information in another format that's called Jason in the past people use a XML but now it's more Jason. So how can we send information. With Jason. By why we do that the reason we do that usually we separate traditionally we had every page that you visit when you click a link would reload or load a new page send from the server. But that changed when they split the concerns between front and the back end meaning we're going to separate the two apps. So we have an app that's only dedicated to the front end to the browser side and we have the app only for the back end that's the server side that handles all the resource and information. So the client side would typically ask for information about a resource and it expects to communicate via HTTP using plain text but the format for the plain text is Jason. So let's learn how to do that here. So let's make an endpoint here. Let's say I want to access resource for products at my shop or something online store. So I'm going to say app dot get and create a new endpoint. This route is for slash products. And function is request res is that an argument. I need to send back products. Typically you'll be an array of objects. So I can create products here an array and put some objects give an ID. Let's say string one and then name of the product. I don't know. Able. And then let's make another one ID to name. Let's do chair and so on. Basically this is the representation of the products a list of products. Each object has a unique identifier for that product and there's a name and in the real world. There'll be probably a lot more information and metadata about the product you know dimensions how much it costs color and so on and so on. Let's keep it simple have only these here. And again these would typically come from a database. So when you ask for resource what would happen here is usually you call on a database to retrieve that information. Since we don't have time for that right now I just put it hard coded in an object. Array of objects but typically that's information would come from the back end the database. So once we create the database get the products array we can finally send it back to the user simply say res dot send and then products and what's nice about express it understands you're going to send Jason. Jason but usually it doesn't hurt to be explicit it might not change the content type. So I was going to make sure that I said res set header or set content type to application slash Jason. This is to tell the client hey we're sending Jason please interpret my response in the Jason format. OK. And by default the status code is 200. I didn't tell you how to change it but if you want to be explicit this rest status 200 like this. You could also change this if you like you can set before you click send you can set status 200 or any other status here like that. So what Cheney means first it sets the status to 200 and it returns the response itself so that you can call send on that again instead of having separate statements. OK. And I think we're good to send the back. Let's watch slash products in the browser. And we see this now Firefox is nice to have this live Jason for you. Let me see the raw data. The raw data is just text. Right. There's no spaces because when you send responses you want to save bandwidth you want to send unnecessary space. But if I click pretty print here I can see better visualize it. And Firefox is the Jason live view where I can expand each element in this array. Now another way if you use another browser that doesn't have this you can always press F 12 or right click inspect to open the dev tools click that work make sure the filters all and refresh you're going to monitor that response for product and you click there. You can see more information. The verb get the endpoint right slash products at the status 200 OK and so on. But you want to look at the response header remember reset the content type on the top application slash Jason is here now express also as this care set your TF 8 I think. And yeah so if I look at the response tab I can see if I click raw this is the raw view is just plain text falling Jason and if I unchecked raw it's going to be the live view from the browser that makes it nice to expand things. We got the point so the client side meaning the web application like the shopping you know catalog application would take this information and inject and in the document to create dynamically generate all the product information that you would see typically product image with some information so people can click there and go to the product page. Any questions so far. Yeah so. When your production you don't want to use node months we probably want to do just node index.js if we can add a script here saying start. When your production you don't want to use node months we probably want to do just node index.js if we can add a script here saying start. Common production dash production whatever that we just know the index.js you're curious. And then if you're in production you just call npm run start colon production. That way it doesn't keep restarting because of node month. Control C to kill that. Yeah going back here to index.js that's pretty much what Express does you're just you know servicing requests from the client side client as for a resource and then you try to find a resource. Look at a database or elsewhere or if it's some data processing that needs to be done whatever it is maybe you want to you know process an image or audio video whatever it is it would be done or called in queue to be done here and eventually. You send back to the user some response. And that's pretty much how it works of course we don't write everything in a single file like I did here. It'll be get really messy right in a real application to have so many endpoints maybe hundreds of them and you want to separate them into different files and to better organize everything. Yeah and with that I think that's it for the introduction to Express.
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? ๐Ÿ˜†๐Ÿ‘
Consider a donation to support our work: