Getting started with Express
If you haven't already set up your Node sample project, you can quickly do so by following these instructions
The http module that we used in a previous activity can be difficult to work with when building web applications. There is an NPM package named Express that we can install, which is built on top of the http module and makes it easier to build various types of web applications. There are other packages available for building web applications, but Express is by far the most popular.
To install the Express package, run this command from the project folder:
npm install express
Remember that whenever you install a module with NPM, the package.json should be updated to document the 'dependencies' for the project.
Now let's use Express to create a web application. Create a file named app.js in the node-sample-project folder (NOT in the 'samples' folder) and put this code in it:
// IMPORTS
const express = require('express');
const app = express();
// MIDDLEWARE
// We'll add 'middleware' code here soon
// ROUTES
app.get('/', (req, res) => {
res.send('<h1>Hello World from Express!</h1>');
});
app.get('/some-route', (req, res) => {
res.send('<h1>This is some route</h1>');
});
// START THE SERVER
const port = 8080; // We'll run the server on port 8080
const server = app.listen(port, () => {
console.log("Waiting for requests on port %s", port);
});
We'll discuss the code in a minute, but first run the application by entering this command in the terminal:
node app.js
Now open a browser tab and navigate to :
http://localhost:8080
You should see a web page that says 'Hello World from Express!'.
Now try visiting this URL in the browser:
http://localhost:8080/some-route
You should see a page that says 'This is some route'.
Note that the terminal is in use right now, because it's running your web application (the web server application is continuously 'listening' for requests from browsers). To stop the server and free up the terminal, press ctrl + c.
Now let's go over the code in app.js.
- First we import the Express module, which happens to be a function.
- Then we invoke the function, which returns an object that represents our web application (which is why the variable name is 'app').
- We'll discuss 'middleware' soon, but in this part of the file we could add features/functionality to our app known as middleware.
- Next we define a 'route' which is a doc root relative path (relative to localhost:8080). The first route is for the website's home page (the path is simply a forward slash). The path for the second route is (/some-route), which means that the callback will be triggered when a request is made for localhost:8080/some-route. I put more info on the routes and callbacks below.
- After the routes are defined, we choose a port for the application to listen to for requests. In this case we chose port 8080. Here's more info on ports.
- The last few lines of code call the listen() method of our application object. The first parameter is the port that the application should use to listen for requests. The second parameter is a callback that will get triggered when the app successfully starts.
Notice that when we define the routes, we call the get() method of the application object. We pass in two parameters. The first parameter is the path (relative to localhost:8080) that will invoke the callback (which is the second parameter). As you saw, when we made a request to localhost:8080/some-route, the callback for that route was invoked and the response sent to the browser was an H1 element that said 'This is some route'. When the app receives a request that matches a route, it will execute the callback function that was defined for the route. Further, Express will pass two parameters into the callback function. The first parameter is an object that represents the incoming request (req) and the second is an object that represents the response that will be sent to the browser (res). Notice that inside the body of the callback, we invoked the send() method of the response object. We used this to add content into the body of the response that the server sends to the browser. We'll be digging much deeper into HTTP requests and responses in the Web 3 and Web 4 classes.But if you want to now more about them now, you can look at this article.
We'll be working with routes in Express a lot more in the final project.
Static Pages and Files
Routes are a powerful tool for building web applications. But we can also use Express to build a traditional website that is made up of 'static' html pages. This approach is very similar to the website that you created in the Web 1 class.
Create a folder named public (put it in the project folder). This folder is the similar to the public_html folder that contains the 'static' web pages for your live site on cPanel (In Express, they decided to just call it 'public').
Inside the public folder, add a file named static-page.html and put this code inside it:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Static Page</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<h1>This is a static page</h1>
</body>
</html>
Now we'll configure the app to use the 'public' folder as a static one.
Add this code to app.js (put it underneath the comment that says MIDDLEWARE):
// set the 'public' folder as the location for our static files:
app.use(express.static('public'));
The use() method of an Express object allows you to add 'middleware' to your application. Middleware allows you to add functionality to your web app. Don't worry too much about this line of code, just know that it designates your 'public' folder as one that will serve 'static' files for your website.
Now stop and restart the server by pressing ctrl + c in the terminal, and then entering node app.js. When you make updates to app.js, you must restart the server in order for the changes to take affect.
Then open this URL in the browser:
http://localhost:8080/static-page.html
You should see the 'static' page in the browser.
The public folder will contain the 'static' files for our website. Static web pages are ones that that don't change. When a request comes in for a static file, the server will simply send the file, as is, to the browser. This is very different from how routes work (we'll talk more about routes in the next section).
Now we'll put other files into the public folder, such as images, .js, and .css files.
Create these folders inside the public folder:
- images
- js
- css
Then put an image in the images folder (any .jpg or .png file will do).
In the js folder, add a file named main.js and put this code in it:
console.log("This is main.js...");
In the css folder, add a file named main.css and put this code in it:
h1{ color: midnightblue; }
Now update static-page.html to look like this (note that you'll have to use the proper name for your image file):
<!DOCTYPE html>
<html lang="en">
<head>
<title>Static Page</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Link to our style sheet -->
<link rel="stylesheet" type="text/css" href="/css/main.css">
<!-- Link to our .js file -->
<script src="/js/main.js"></script>
</head>
<body>
<h1>This is a static page</h1>
<img src="/images/eagle.png"><!---------USE YOUR OWN IMAGE HERE-->
</body>
</html>
Now reload the page in the browser (http://localhost:8080/static-page.html), and note the following:
- Your image should appear on the page.
- The H1 element should be blue (because we linked the page to the stylesheet)
- If you check the console log, you should see that the JavaScript code in main.js has executed.
Note that the links to the static files start with a forward slash. These paths are known as doc root relative links. When we added the middleware code to app.js, we designated the public folder as the root folder for our static files. This means that any link path that begins with a forward slash will start in the public folder and follow the rest of the steps in path from there.
Nodemon
It gets to be tedious to stop and start the app each time you make changes (first you have to press ctrl + c to top the app, then you have to enter node app.js to restart it).
There is an NPM package that you can install that will automatically restart the app when you save changes to a file. The package is called nodemon, and you can install it by running this command (from the project folder):
npm install nodemon --save-dev
Note that the --save-dev option indicates that this package will only be used when we are developing the app. And therefor, the package should not be included when we deploy the app to our live server. If you look in the package.json file, you should see that nodemon is listed as a devDependency.
Now that you've installed nodemon, you can use it to start your app like so:
npx nodemon app.js
Nodemon will 'watch' for when you save changes to your project files, and it will automatically stop and restart the app for you.
Nodemon is a little different than the other NPM packages we've installed. It is an executable program that runs and watches for changes to files in your project folder. To run an executable package, you need to enter npx followed by the name of the package. For more info on npx, checkout this article.
Dynamic Pages (Routes)
In contrast to static files, our website may also include dynamic 'pages'. We've already added two 'routes' in app.js, these can also be called 'dynamic pages'.
Routes are called 'dynamic pages' because they allow us to run some code on the server before sending the response to the browser. They are not really 'pages', like .html files in the public folder, but they look like pages to the end user. Instead, they execute the 'route handler' functions, which are the callbacks that you define for a route. Remember that when that app receives a request that matches one of it's routes, it will trigger the callback for that route. These callbacks are also called 'route handlers' because they do just that (handle an incoming request for a route).
Here's an example, add this code to the ROUTES section of app.js:
app.get("/dynamic-page.html", (req, res) => {
const currentTime = new Date();
res.send(`<h1>The current time is ${currentTime.toString()}</h1>`);
});
Hopefully nodemon will automatically stop and restart the server for you. Then visit this page in the browser:
http://localhost:8080/dynamic-page.html
If you refresh the page in the browser you'll see that the server responds with different content every time, which is why we call it a dynamic page. Dynamic pages (routes) allow you to run code on the server before sending a response to the browser. While static pages do not change (unless you actually change the file).
In this example, the server is simply computing the current time and sending it in the response. But you could do much more complicated and useful things by running code on the server. For example, you run code on the server that connects to a database and embeds the results of a SQL query in the response before sending it to the client. We'll be doing a lot of this in the Web 4 class!
Commit your changes to your Git repository.
Then create a separate branch, so that we can easily return our project to the current state if we need to. Run this command:
git branch 6-express-complete
Finally, make sure to push this branch, and your main/master branch to GitHub.
In the next lesson, you'll learn about EJS Templates