Node.js series Part 1. Create a Simple Web-Server with Node.js

Node.js series Part 1. Create a Simple Web-Server with Node.js

8. März 2020 Aus Von admin

In this part 1 of my node.js series I briefly explain the creation of a simple node.js web-server that respond to various http requests. I explain the basics of Node.js and install the Express.js framework so that it can be used by the simple web-server.

Chapter 1: Under the hood of the simple web-server

Node.js is based on JavaScript. JavaScript has always been known as a front-end programming language that is executed in the browser. The code runs in the browser. This has changed since node.js because with node.js JavaScript code is executed on the server side. The code no longer runs in the browser but on the server. Node.js provides the build in http module which make it easy to implement a web-server with basic functionalities. Node.js is a runtime environment in which server-side code can be executed. In this respect, node.js is the basic technology for frameworks like Express.js.

Express.js is the most widespread node.js framework. In contrast to the pure node.js http module, Express.js offers extensive options for processing client http requests. Express.js also offers middleware functionalities that can be built in between the request and the response to execute the code build in routes depending on the middleware function. This includes authentication and authorization, logging and much more.

Chapter 2: Install node.js and npm

First of all, it must be ensured that node.js and also npm.js are installed on your system. npm is the node package manager and is absolutely necessary if we develop programs with node.

We should definitely check whether node and npm are already installed on the system. To do this, please enter the following commands on the command line.

Patricks-MBP:node patrick$ node --version
v13.8.0

Patricks-MBP:node patrick$ npm --version
6.13.7

Patricks-MBP:node patrick$ 

In this case, node is already installed in version 13.8.0 and npm in version 6.13.7 and nothing further needs to be done.

I work with Mac OS and there is the standard for installing command line tools homebrew. I wrote the article node.js and npm on Mac OS here on Digitaldocblog that shows step by step the installation of node and npm on a Mac OS. Other ways to install node.js can be found on [nodejs.org] (https://nodejs.org/en/download/).

Especially if we work with Ubuntu linux, node and npm can be installed using the Advanced Packaging Tool (APT). While on Mac OS the installation of node using homebrew includes npm, node and npm are installed separately on Ubuntu. Simply enter the following commands on the command line on your Ubuntu system (but check before if it is already installed).

#: sudo apt install nodejs

#: sudo apt install npm

Of course, it is also a basic requirement to install a suitable editor. You can of course also work with text editors like nano or vi, but that is certainly very cumbersome. From my point of view, the Atom editor is very suitable for node programming and my first choice.

After that, the following requirements should be met:

  • node and npm installed
  • text editor installed (i.e. Atom)

Chapter 3: The basics of node.js

I will briefly go over here to explain how node.js works. For this I will program a simple webserver with plain node.js and you can see what node already offers for creating a web app.

For this purpose, a separate directory for our first node web-app is created on the development system. This is the place we will store all files and the entire program code and called the application root directory. In my case this is the application root directory node-basic.

Patricks-MBP:2020-03-08 patrick$ mkdir node-basic

Patricks-MBP:2020-03-08 patrick$ cd node-basic

Patricks-MBP:node-basic patrick$ ls -al
total 0
drwxr-xr-x  2 patrick  staff  64 08 Mär 06:05 .
drwxr-xr-x  3 patrick  staff  96 08 Mär 06:05 ..

Patricks-MBP:node-basic patrick$ pwd
/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic

Patricks-MBP:node-basic patrick$  

Change to the application root directory you just created, create a file server.js and open this file using your favorite editor. The file server.js is called the application main file and is the entry point of our node web-application.

Patricks-MBP:node-basic patrick$ touch server.js

Patricks-MBP:node-basic patrick$ ls -l
total 0

-rw-r--r--  1 patrick  staff  0 08 Mär 18:22 server.js

Patricks-MBP:node-basic patrick$ 

3.1 Simple node web-server using the integrated ‚http‘ module

Enter the following code in server.js. You can find the code on my GitHub Page.

// server.js

// 1. load http module
const http = require('http')

// 2. create the server
const server = http.createServer(function (req, res) {

    // 3. check conditions for requests
    if (req.url == '/') {

        // 4.1 set response header
        res.writeHead(200, { 'Content-Type': 'text/html' });

        // 4.2 set response content
        res.write('<html><body><p>This is my home Page.</p></body></html>');
        
        // 4.3 End response
        res.end();

    }
    else if (req.url == "/about") {

        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('<html><body><p>This is my about Page.</p></body></html>');
        res.end();

    }
    else if (req.url == "/impressum") {

        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('<html><body><p>This is my Impressum Page.</p></body></html>');
        res.end();

    }
   else {
      res.writeHead(404, { 'Content-Type': 'text/html' })
      res.write('<html><body><p>This path is not available. Invalid request</p></body></html>')
      res.end()
    }
});

// 5. server listen for any incoming requests
server.listen(3000);

console.log('My node.js web server is alive and running at port 3000')


A webserver is a relatively simple system that processes HTTP requests from a client. node.js contains the http module with which the developer can program http server but also http clients.

So lets see what happens in the code above.

  1. The http module is loaded with the require() function and a reference is saved in the variable http. Various functions can be used on the http reference that are provided by the http module.
  2. On the http reference a server is created with the http.createServer() function. http.createServer() creates a server object and the reference is saved in the variable server. The server object can listen to ports and receives a requestListener() function as parameter. This function is always executed when the server receives a request from the client and expects 2 parameters such as request and response. These parameters are usually noted with req and res.
  3. req is always the first parameter and represent the request object. The request object refer to the IncomingMessage object. This object has properies and methods like the property url that can be used with req.url.
  4. res is always the second parameter and represent the response object. The response object refer to the ServerResponse object. This object has properties and methods like the method writeHead() that can be used with res.writeHead().
  5. In the if and else if block we compare the requested url req.url with the url we difined in our route (i.e. „/“ or „/about“). For example, if the URL corresponds to „/about“, the server should return an about page to the client. If the requested url req.url does not match any of the conditions specified with if and else if, an error message is sent back to the client.
  6. res.writeHead(): the function writeHead() sends the http-status code 200 (Ok) as the standard response for successful HTTP requests and the response header back to the client. The response header is an object with the key content-type and the value text/html as here in the example. In case the requested url req.url does not match any of the conditions specified with if and else if writeHead()* sends the http-status code 404 (Not Found).
  7. res.write(): The function write() sends a text stream back to the client. In our example write() send HTML that can be parsed by the browser to display a website content.
  8. res.end(): the end() function tells the server that the request has ended.
  9. At the end of the program, the listen() function is used on the server, which expects the port as the parameter. The port in this example is port 3000. listen() starts the server on port 3000 at the localhost.
  10. The final statement log a message at the console that the server has been started.

3.2 Code encapsulation using self-developed modules

In our webserver example we load the node.js integrated http module with the require() function and we used the method createServer() with a requestListener() function that contains the entire server logic.

We write all the code in the server.js application main file which make the code confusing especially when we program more complex applications.

Node offers the possibility to encapsulate code in a separate file. When we have code in a separate file then we speak of a module. Like the integrated http module we load this module into the application main file server.js using the require() function.

With the help of directories you can structure your modules effectively. In this example I want to collect all my modules in a directory called modules. In this directory I create the logic.js file that contain all the server logic.

You can find the code on my GitHub Page.

Patricks-MBP:node-basic patrick$ ls -l
total 8
-rw-r--r--  1 patrick  staff  1282 08 Mär 05:58 server.js

Patricks-MBP:node-basic patrick$ mkdir modules

Patricks-MBP:node-basic patrick$ ls -l
total 8
drwxr-xr-x  2 patrick  staff    64 08 Mär 07:31 modules
-rw-r--r--  1 patrick  staff  1282 08 Mär 05:58 server.js

Patricks-MBP:node-basic patrick$ touch modules/logic.js

Patricks-MBP:node-basic patrick$ ls -l modules
total 0
-rw-r--r--  1 patrick  staff  0 08 Mär 07:31 logic.js

Patricks-MBP:node-basic patrick$ 

The server logic that is executed whenever the server receives a request should be in the modules/logic.js file. The modules/logic.js file contains the following code.

// modules/logic.js

const serverlogic = function(req, res) {
    // check conditions for requests
    if (req.url == '/') {

        // set response header
        res.writeHead(200, { 'Content-Type': 'text/html' });

        // set response content
        res.write('<html><body><p>This is my home Page.</p></body></html>');
        // End response
        res.end();

    }
    else if (req.url == "/about") {

        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('<html><body><p>This is my about Page.</p></body></html>');
        res.end();

    }
    else if (req.url == "/impressum") {

        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('<html><body><p>This is my Impressum Page.</p></body></html>');
        res.end();

    }
    else {
      res.writeHead(404, { 'Content-Type': 'text/html' });
      res.write('<html><body><p>This path is not available. Invalid request</p></body></html>');
      res.end();
    }
  }

  module.exports = serverlogic;

The function with all instructions is assigned to the constant serverlogic. At the end of the file, the reference to the function is exported with module.exports. The function serverlogic() is now usable in other files of the application.

In order to integrate the new self-developed module into the server.js file, we use the require function again as follows.

// server.js

// load http integrated node module
const http = require('http')

// load self-developed module serverlogic from modules/logic.js
const serverlogic = require('./modules/logic');

// create the server
const server = http.createServer(serverlogic);

// 5. server listen for any incoming requests
server.listen(3000);

console.log('My node.js web server is alive and running at port 3000')

With the require() function we load the file modules/logic in the server.js application and assign the constant serverlogic. Now we can use the module in the createServer() method and the server runs exactly as before.

3.3 Using third-party modules

In our webserver example above we see how we can create a simple webserver using the node on-board resources. In our example we include the node.js integrated http module, which has been loaded with the require function and we used methods like createServer() that are provided by this integrated module. And we see how we can encapsulate the server logic to a separate file.

In general the scope of integrated node.js modules such as the http module is very minimal and is limited to the absolutely essential, which means that the node.js core is very compact and stable. The node.js core offers a very mature and stable runtime environment, but there is no comprehensive standard library to develop more complex web-applications easily. Therefore hundreds of thousands different third party modules from the node community are available.

Express.js is one of the most used third-party modules to create web-applications. The advantage of a module like Express is that this module contains many methods optimized for the http request handling. When using Express, for example the functions such as writeHead(), write() and end() can be replaced by one single function res.send(). And the node community offers many other third party modules that are tailored to the use of Express.

In order to use a third party module in a web application, it must be installed in the application root directory. The installation is done by the node package manager in the application root directory. Third party modules are also called dependencies. This means the application that lives in the application root directory and is defined by the various js-files contains dependencies of the installed third party modules.

I will therefore first delete the self-developed module so that I only have the application main file server.js in the application root directory.

Patricks-MBP:node-basic patrick$ ls -al
total 8
drwxr-xr-x  4 patrick  staff  128 08 Mär 18:10 .
drwxr-xr-x  3 patrick  staff   96 08 Mär 06:05 ..
drwxr-xr-x  3 patrick  staff   96 08 Mär 07:31 modules
-rw-r--r--  1 patrick  staff  387 08 Mär 07:51 server.js

Patricks-MBP:node-basic patrick$ rm -r modules

Patricks-MBP:node-basic patrick$ ls -al
total 8
drwxr-xr-x  3 patrick  staff   96 08 Mär 06:07 .
drwxr-xr-x  3 patrick  staff   96 08 Mär 06:05 ..
-rw-r--r--  1 patrick  staff  387 08 Mär 07:51 server.js

Patricks-MBP:node-basic patrick$

The third party module Express can now be easily installed in the application root directory as follows.

Patricks-MBP:node-basic patrick$ pwd
/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic

Patricks-MBP:node-basic patrick$ npm install express
npm WARN saveError ENOENT: no such file or directory, open '/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic/package.json'
npm WARN node-basic No description
npm WARN node-basic No repository field.
npm WARN node-basic No README data
npm WARN node-basic No license field.

+ express@4.17.1
added 50 packages from 37 contributors and audited 126 packages in 2.215s
found 0 vulnerabilities

Patricks-MBP:node-basic patrick$ ls -al
total 40
drwxr-xr-x   5 patrick  staff    160 08 Mär 06:14 .
drwxr-xr-x   3 patrick  staff     96 08 Mär 06:05 ..
drwxr-xr-x  52 patrick  staff   1664 08 Mär 06:14 node_modules
-rw-r--r--   1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--   1 patrick  staff    387 08 Mär 07:51 server.js

Patricks-MBP:node-basic patrick$ 

The third party module Express.js in version 4.17.1 has been installed successfully in the application root directory. Express.js is now available locally in our application perimeter and can therefore be used in the application.

In the application root directory we see the following changes.

  • node_modules: the node_modules directory is created during the installation. npm stores all locally installed packages there. If you look into the directory you will see that there is currently more than just the Express module installed. This is due to the fact that Express itself requires modules which in turn were taken into account during this installation and were also installed.
  • package-lock.json: The package-lock.json file is always generated automatically when npm changes the directory content in node_modules. The content of the package-lock.json shows the current complete directory tree of all modules and if you want to install an additional module or dependency it is ensured that the installation process creates exactly the directory tree at the end of the existing plus the directory of the newly installed module.

It is possible to install several modules in this way in order to use them in the application. If you continue installing modules, you will quickly lose track of which modules are installed in which version.

It is then no longer easy to depoloy the application, for example, from a Mac OS developer system to a Linux production system and keep exactly the same version of the modules used. The goal must be to install all the modules used in development in exactly the same way on another system or in another application root directory. Here node offers a possibility to do this with the help of the package.json file.

The package.json file is in your application root directory and list all modules or packages that have been installed in your application root directory. In node it is said that modules are packages and that an application depends on packages. In this respect, the package.json file lists all the packages on which your application depends on.

In order to demonstrate how we use a package.json file when installing the Express package, I will delete the node_modules directorory again and create a package.json file.

Patricks-MBP:node-basic patrick$ pwd
/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic

Patricks-MBP:node-basic patrick$ ls -l
total 40
drwxr-xr-x  52 patrick  staff   1664 08 Mär 06:14 node_modules
-rw-r--r--   1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--   1 patrick  staff    524 08 Mär 09:34 server.js

Patricks-MBP:node-basic patrick$ rm -r node_modules

Patricks-MBP:node-basic patrick$ ls -l
total 40
-rw-r--r--  1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--  1 patrick  staff    524 08 Mär 09:34 server.js

Patricks-MBP:node-basic patrick$ touch package.json

Patricks-MBP:node-basic patrick$ ls -l
total 40
-rw-r--r--  1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--  1 patrick  staff      0 08 Mär 07:19 package.json
-rw-r--r--  1 patrick  staff    524 08 Mär 09:34 server.js

Patricks-MBP:node-basic patrick$

With the following command using the npm init –yes I create a default package.json file as follows. This guarantees a correct .json format with a standard structure and node or npm will not throw any error messages with this package.json file when you install packages.

Patricks-MBP:node-basic patrick$ ls -l
total 48
-rw-r--r--  1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--  1 patrick  staff    106 08 Mär 07:39 package.json
-rw-r--r--  1 patrick  staff    526 08 Mär 07:40 server.js

Patricks-MBP:node-basic patrick$ npm init --yes
Wrote to /Users/patrick/Software/dev/node/myArticles/2020-03-08/node-
basic/package.json:

{
  "name": "node-basic",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


Patricks-MBP:node-basic patrick$

note: With the command npm init –yes default values are set in the package.json file. For example, the value of name is assigned to the directory name, the version is always 1.0.0 and main is usually index.js unless like in our case npm finds a server.js file that differs from index.js.

This package.json file can now be adjusted with our preferred editor according to our preferences. My personal preference is to keep the package.json file as simple as possible, so the default content for me is as follows.

{
  "name": "simple_webserver",
  "version": "0.0.1",
  "main": "server.js",
  "author": "Patrick Rottlaender"
}

Then I install Express.js again using the command npm install express --save.

Patricks-MBP:node-basic patrick$ ls -l
total 48
-rw-r--r--  1 patrick  staff  14240 08 Mär 06:14 package-lock.json
-rw-r--r--  1 patrick  staff    256 08 Mär 07:44 package.json
-rw-r--r--  1 patrick  staff    526 08 Mär 07:40 server.js

Patricks-MBP:node-basic patrick$ npm install express --save
npm WARN node-basic@1.0.0 No description
npm WARN node-basic@1.0.0 No repository field.

+ express@4.17.1
added 50 packages from 37 contributors and audited 126 packages in 2.895s
found 0 vulnerabilities

Patricks-MBP:node-basic patrick$ ls -l
total 48
drwxr-xr-x  52 patrick  staff   1664 08 Mär 07:46 node_modules
-rw-r--r--   1 patrick  staff  14286 08 Mär 07:46 package-lock.json
-rw-r--r--   1 patrick  staff    306 08 Mär 07:46 package.json
-rw-r--r--   1 patrick  staff    526 08 Mär 07:40 server.js

Patricks-MBP:node-basic patrick$ 

As you can see, the node_modules directory has also been created, in which the express module and all of its dependencies can now be found. Let’s take a look at the content of the package.json file, we see that a new object dependency has been added and we see that express in version 4.17.1 exists there.

{
  "name": "simple_webserver",
  "version": "0.0.1",
  "main": "server.js",
  "author": "Patrick Rottlaender",
  "dependencies": {
    "express": "^4.17.1"
  }
}

A very important point is the spelling of the version of the installed dependency in the package.json file. In our example express was installed in version „^ 4.17.1“. The preceding „^ …“ tells npm to install a version of at least version 4.17.1 or higher when calling npm install. This means that until the change to a new major version 5, npm would always update to the latest version. This can lead to problems in an application because when versions of dependencies are changed, the code may no longer be compatible and the code must be adapted.

Therefore I always recommend to remove the preceding „^ …“ to tell npm that the exact version has to be kept when calling npm install.

The following is the content of the package.json file.

{
  "name": "simple_webserver",
  "version": "0.0.1",
  "main": "server.js",
  "author": "Patrick Rottlaender",
  "dependencies": {
    "express": "4.17.1"
  }
}

note: It is also possible to tell npm at the time of the installation of a package that the latest version must be installed initially but the entry in the package.json file will be made without the preceding „^ …“. Then npm install does not update the version that is in the package.json file.

Using the example of the installation of express, the installation would be carried out with the following command: npm install express –save –save-exact.

If we assume we want to install exactly the same packages as dependencies in another directory or even on a different computer, we would proceed as follows. This is exactly the scenario when we have developed and tested an application and now want to bring this application into the production environment.

  • we create a new target application root directory (new target directory)
  • we copy the package.json file into the new target directory
  • we copy the application files, in our case this is just the file server.js in the new target directory
  • we change to the new target directory
  • We run the command npm install without any other option
Patricks-MBP:node-basic patrick$ pwd
/Users/patrick/Software/dev/node/myArticles/2020-03-08/node-basic

Patricks-MBP:node-basic patrick$ ls -l
total 48
drwxr-xr-x  52 patrick  staff   1664 08 Mär 09:26 node_modules
-rw-r--r--   1 patrick  staff  14300 08 Mär 09:26 package-lock.json
-rw-r--r--   1 patrick  staff    171 08 Mär 09:26 package.json
-rw-r--r--   1 patrick  staff    526 08 Mär 07:40 server.js

Patricks-MBP:node-basic patrick$ cd ..

Patricks-MBP:2020-03-08 patrick$ ls -l
total 0
drwxr-xr-x  6 patrick  staff  192 08 Mär 09:26 node-basic

Patricks-MBP:2020-03-08 patrick$ mkdir express-basic

Patricks-MBP:2020-03-08 patrick$ ls -l
total 0
drwxr-xr-x  2 patrick  staff   64 08 Mär 09:39 express-basic
drwxr-xr-x  6 patrick  staff  192 08 Mär 09:26 node-basic

Patricks-MBP:2020-03-08 patrick$ cp node-basic/package.json express-basic
Patricks-MBP:2020-03-08 patrick$ cp node-basic/server.js express-basic

Patricks-MBP:2020-03-08 patrick$ cd express-basic

Patricks-MBP:express-basic patrick$ ls -l
total 16
-rw-r--r--  1 patrick  staff  163 08 Mär 10:03 package.json
-rw-r--r--  1 patrick  staff  526 08 Mär 09:40 server.js

Patricks-MBP:express-basic patrick$ cat package.json

{
  "name": "simple_webserver",
  "version": "0.0.1",
  "main": "server.js",
  "author": "Patrick Rottlaender",
  "dependencies": {
    "express": "4.17.1"
  }
}

Patricks-MBP:express-basic patrick$ npm install

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN simple_webserver@0.0.1 No description
npm WARN simple_webserver@0.0.1 No repository field.
npm WARN simple_webserver@0.0.1 No license field.

added 50 packages from 37 contributors and audited 126 packages in 1.864s
found 0 vulnerabilities

Patricks-MBP:express-basic patrick$ ls -l
total 48
drwxr-xr-x  52 patrick  staff   1664 08 Mär 10:05 node_modules
-rw-r--r--   1 patrick  staff  14292 08 Mär 10:05 package-lock.json
-rw-r--r--   1 patrick  staff    163 08 Mär 10:03 package.json
-rw-r--r--   1 patrick  staff    526 08 Mär 09:40 server.js

Patricks-MBP:express-basic patrick$  

Chapter 4: The simple webserver using the Express.js module

We are now working in the following directory. You can find the code on my GitHub Page.

Patricks-MBP:express-basic patrick$ pwd
/Users/patrick/Software/dev/node/myArticles/2020-03-08/express-basic

Patricks-MBP:express-basic patrick$ 

If we now want to use the Express module in our web application, we have to load the express module with the require() function. The express module returns a function and this function is stored in the constant express. When you call the express() function an app object will be returned. This app object will be now stored in the const app and can now be used in the server.js file. The code in server.js is now as follows.

// server.js

// load http module
const http = require('http')

// load the Express module
const express = require('express')

const app = express()

// create the server
const server = http.createServer(app);

// server listen for any incoming requests
server.listen(3000);

console.log('My express web server is alive and running at port 3000')

As we can see in the code, we are now using the app as a parameter for the createServer() function. createServer() therefore creates and express web-server. Now lets run the code with node server.js and see what happens.

Patricks-MBP:express-basic patrick$ node server.js
My express web server is alive and running at port 3000

Perfect! The express server is running on localhost port 3000. But if we enter http://localhost:3000 in the browser we get an error message Cannot GET /. This is actually clear since we have not yet defined any routes in the code that tell the server how to respond to a request for the route „/“.

But there is something else interesting: the response of the server with the text Cannot GET / is already a website. That means Express already takes over for us the part of the error handling that we programmed without Express in the code above in a specific instruction.

This becomes even clearer when we issue an http request in the terminal with the help of the curl program.

Patricks-MBP:express-basic patrick$ curl -i http://localhost:3000
HTTP/1.1 404 Not Found
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 139
Date: Sun, 15 Mar 2020 06:15:11 GMT
Connection: keep-alive

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /</pre>
</body>
</html>

Patricks-MBP:express-basic patrick$ 

note: curl is a program to transfer data from and to a server. curl supports some protocols including http. The -i option include the HTTP response headers in the output. The HTTP response headers include i.e. HTTP version, Content-Type, Date etc.

In the curl output above you can exactly see that the response from the server is a 404 Not Found http code and an html document to display an error HTML document in the browser. This is something that Express do for us.

So now we have to define routes to tell the server what to send in response when a particular route is requested. There are Express functions for certain http verbs like get(), post(), put() or delete() already available in Express. These functions are used on the app, which we referenced in our code with the constant app. So lets change our code as follows.

// server.js

// load http module
const http = require('http')

// load the Express module
const express = require('express')

const app = express()

// define the routes
app.get('/', (req, res) => {
  res.send('Hello, this is my home Page')
})

app.get('/about', (req, res) => {
  res.send('Hello, this is my about Page')
})

// create the server
const server = http.createServer(app);

// server listen for any incoming requests
server.listen(3000);

console.log('My express web server is alive and running at port 3000')


As you see I added a route definition for get(). The http verb functions like get() expect two parameters:

  1. the route to be defined
  2. the http handler which is transferred as a callback function with the parameters req and res. This http handler will give the server the instructions it needs to respond to the request for this particular route. Other routes like /about require a separate route definition.

We start server.js again and request the routes via the browser with http://localhost:3000 and http://localhost:3000/about and find that the response defined in res.send is sent as HTML from the server. Thats good.

With curl and requesting route /about we get the following terminal output.

Patricks-MBP:express-basic patrick$ curl -i http://localhost:3000/about

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 28
ETag: W/"1c-qDZjsFWQH9PGrhmVTBEfY+9a0Fo"
Date: Sun, 15 Mar 2020 05:44:19 GMT
Connection: keep-alive

Hello, this is my about Page

Patricks-MBP:express-basic patrick$

The curl output now show 202 Ok http code and the html document content Hello, this is my about Page. So its all working fine so far.

Summary and Outlook

In this Part 1 I created a simple node.js web-server that respond to various http requests from a browser. I explained the basics of Node.js such as the installation of node and npm, the use of modules and configuration of the package.json file. Then I installed the Express.js framework as a dependency of my server application and configured it so that it can be used by the simple web-server.

In the following Part 2 of this node.js series I will explain the Express.js framework much more in detail. We will learn something about web api(s) and we will understand how we can use Express as middleware in a web application. And we will create a small blog application.