Today we are going to build a web server. In particular we want to understand the difference between static and dynamic content. We are going to set up a simple express server, and also use some templating to create dynamic content.
Have your project with the Restaurant models handy.
What is a server? The simple answer is a computer that provides services to other computers. From that definition you can tell servers are often found on networks. For example an office might have a 'file server' a computer where office workers can read and write files that can be accessed by any other computer on the network.
In this lesson we are going to focus on creating a 'web server' and an 'app server' using the Express web framework for Node.js.
A 'web server' responds to requests for .html
files by sending back the .html contents of that file.
Tp create a web server we firstly install the node module 'express' using npm install express
. Next we create a file called server.js
containing the following logic:
const express = require('express');
const app = express();
const port = 3000;
// serve static assets from the public/ folder
app.use(express.static('public'));
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`)
})
After importing the express module we create an instance of a web server and call it app
. Then we configure the server to serve 'static' assets from the 'public' folder. A 'static' asset is a file that is simply read off of disc and then returned to the user.
We then need to add an html file in our public
folder called index.html
. For now it can just be a very simple "hello world" page, see below. Naming the file index.html
makes it the default page express will respond with when requests are made to the root of the server.
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello World</h1>
</body>
</html>
To start your server from the root of your project run the command node server.js
you should see your message being logged out and now your web server is running. Visit http://localhost:3000/
to see your html page.
Your server will serve your html page to any other computer that asks for it. The computer needs to be publicly accessible, so it will not work on your computer, unless you expose it to the wider internet, or deploy your server code online.
We can serve different kinds of files from our public folder. For example a .css file or a javascript file. Let's try to add some style to our html page using a style.css
file.
* {
padding: 0;
margin: 0;
}
body {
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
color: rgb(35, 1, 35);
background-color: rgb(255, 228, 225);
}
Now we update our index.html
file to also request this file from the server.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css"/>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
Notice the "/style.css"
this is not a file path. It is a URL ( Uniform Resource Locator). The browser will actually read this URL as http://localhost:3000/style.css
and if you visit that in your browser you'll see the content of your css.
So, in summary, when a request is made to our web server for the index.html
page, when that loads in the browser the index.html
page makes a request for another file, our style.css file.
Under Developer Tools
in your Chrome browser you should be able to see in the Network
tab, the request the index.html page makes for the style.css
file. Once all these additional requests for assets and files have finished, the browser document
will emit an 'onload' event signalling your page has loaded.
npm init
to create a new projectnpm install express
public
directoryindex.html
page with a linked css filehttp://localhost:3000/
to see your html pageNetwork
section of your browser's Developer Tools
. Look at the HTTP status codes, what happens to them when you refresh?<a href="/about.html">About me</a>
Note: If you get stuck, here is the solution to Lesson 1
What makes content static? Static content is usually read from disc, it is the same every request, it is the same for everyone. Examples include, image files, .mp3 files, html files etc. We have been working with static files so far on our web server.
Dynamic content is content that can change from request to request, and might be different for different people. For example everyone has the same basic Facebook page, but each person's page is filled with content that is particular to them. What is shared between users is the page's template. The content is changeable or dynamic.
So where does the dynamic content come from? Dynamic content is usually stored in a database, or comes from another service. The app responds to a request by fetching some specific content for that user/request and parses that content with a template to create the resulting html. The page is built per request "on-the-fly" and is assembled by our app.
If we are serving dynamic content like this our server is now called an app server.
Our server needs to intercept the HTTP request. It's no good just responding with the content of a static file or template. The way we intercept or 'handle' requests is by declaring a 'route' in our server.js file. Here is an example route which returns the current date when the user navigates to the root URL e.g. http://localhost:3000:
app.get('/', (request, response) => {
const date = new Date()
response.send(date)})
Route definitions appear after setting config with app.use
, but before the call to app.listen
.
Be sure to remove the public/index.html
file as that will interfere with your /
route.
Our dynamic content is going to be driven by our Restaurant data model. We will want to display our list of restaurants within a web page. For this, we are going to use a templating framework called Handlebars. This is a well supported template library in which you write html and have place holders for dynamic content.
A Handlebars expression is content surrounded by {{
}}
. When the template is executed, the expression is replaced with values from an input object.
Handlebars expects a specific folder structure:
views
├── restaurants.handlebars
└── layouts
└── main.handlebars
The views
folder contains Handlebars templates which get rendered into layouts
.
A layout
is an HTML page with a {{{body}}}
placeholder into which views are rendered. The layouts
folder typically holds a default main.handlebars
layout.
In our Restaurants app we will set the main.handlebars
layout as follows:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css"/>
</head>
<body>
{{{body}}}
</body>
</html>
The restaurants.handlebars
file will be rendered in the main.handlebars
layout and for now, will simply print out the date.
<h1>Restaurants</h1>
<small>{{date}}</small>
To install Handlebars, run npm install handlebars express-handlebars @handlebars/allow-prototype-access
. Once installed, the code is used as below:
const express = require('express');
const Handlebars = require('handlebars')
const expressHandlebars = require('express-handlebars')
const {allowInsecurePrototypeAccess} = require('@handlebars/allow-prototype-access')
const app = express();
const port = 3000;
// setup our templating engine
const handlebars = expressHandlebars({
handlebars: allowInsecurePrototypeAccess(Handlebars)
})
app.engine('handlebars', handlebars)
app.set('view engine', 'handlebars')
// serve static assets from the public/ folder
app.use(express.static('public'));
// this route matches any GET request to the top level URL
app.get('/', (request, response) => {
response.render('restaurants', {date: new Date()})
})
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`)
})
(optional) - watch these video to reinforce your learning:
Modify server.js
to serve both static and dynamic content as per the code above. Start your server by navigating to http://localhost:3000
. You should see the date displayed. Use Developer Tools
to see the HTTP requests as you refresh the page
Create another route handler on your server, /about
Create another template in the views
folder for your new /about
page
Add a link from the restaurants
page to the about
page
Display your name on the about page
Note: If you get stuck, here is the solution to Lesson 2