Introduction to Express.js - Basic routing

This post is Part 1 of a series on Express.js and how it works on a basic level. Express.js is a cool framework and has of course much more to provide than I can present in a blog. I will cover the most basic aspects of the framework here.

First, let’s see how to create a simple web server and create some pages which return different messages when their URL is entered in the browser.

What is Express.js?

Express.js is a lightweight web application framework for Node.js. It’s a great extension tool which keeps all the features of Node.js, so they are also available in Express.js. It can be used to create API endpoints with more flexibility.

Installation

In order to use Express you need to have Node.js installed on your computer. If you don’t have Node.js, follow the link and download the latest stable version (LTS) and just click on the installation file.

Installing Express is really easy. We need to navigate into the project folder and run npm init from the terminal. This process will generate a bunch of questions, just press Enter to all of them, the answers don’t really matter for now.

This step creates the package.json file containing some important pieces of information (dependencies, script commands) about the application.

Basic Express server

The next step is to install Express.js. Type npm install express --save in the terminal. This will install the latest stable version (4.16.x at the time of writing this) of Express.js in the project folder.

Express provides us with a generator as well, which is similar to Angular CLI. It can be useful in some cases as it creates folders for the user and does the scaffolding for them. I rarely use it though because I like to create folders and files for the server and routes and Express has much less difficult folder structure than, say, Angular does. Neither do I use template engines because I prefer front end libraries and frameworks such as Angular or React.

That’s it about me, and now let’s get back to Express because npm has finished installing it by now.

Create a file called server.js in the project folder and require Express at the top of the file:

const express = require('express');

express is a function and we need to call it in order to access the features we want to use. Let’s save the result in variable called app:

const app = express();

app is an object and has a bunch of methods available for us to work with. For our purpose (creating a basic web server) we will first use the listen method.

listen accepts some optional arguments. The first argument is the port which we want our server to run on. It’s useful to enter this parameter in most cases, so let’s declare and define it here and then add it to listen:

const PORT = 3000;

app.listen(PORT);

That’s it. All we have to do now is to type node server.js in the terminal, press Enter and navigate to localhost:3000 in the browser.

At least two minor problems arise with this setup and luckily, they are easy to fix.

First, chances are that you will see something similar: Cannot GET /. This is an error warning from Express that we haven’t defined any routes at all.

Second, we don’t know if the server is running. It probably is but if you are like me and like to see some confirmation, we’ll need to add something to the code.

Let’s remedy the first issue first. Somewhere above app.listen(PORT), we need to declare what should happen when we visit localhost:3000 in the browser. This is the root of the application, the page the visitor first sees and somehow we need to advise the server what response it should give us when localhost:3000 is hit.

Here we use the get method available on app. get is one of the routing methods, and as its name implies it’s used to get or receive some information relevant to the route.

In our case, as it’s the root, we’ll need to write something like this:

app.get('/', (req, res) => {
  res.send('Response from server');
});

get can also accept multiple arguments. The first should be the path, which is a string. In our case, we want to get some response when we hit localhost:3000 without anything else added, so we need to write '/' in the first argument.

Then at least one callback function must follow. This callback function will advise the server what to do after someone has hit the localhost:3000 path in the browser.

This callback function comes with two arguments, req, referring to the request object and res, standing for the response object. The request and response objects are exactly the same as those in Node.js, and their methods are also available here.

To keep things simple for now, we only use res here and send some response from the server using the send method.

If you now stop the server with Ctrl + C and start it again, you will see “Response from server” written in the browser window.

The second issue, which is not really an issue, it’s just something that I like to do when developing, is logging to the console. listen accepts a callback function as the last argument and we can display some information with the help of it. I would change the last line to something like this:

app.listen(PORT, () => console.log(`Server is running on port ${ PORT }`));

Although not necessary, it’s useful because I can see in the console when the server starts or restarts.

If you restart the server by pressing Ctrl + C and then up arrow key again, the server should stop and you should see node server.js in the terminal again. Press Enter, and you will see “Server is running on port 3000” in the console. Now we know that no error has occurred with the server and it’s up and running.

Basic routing

We have a basic webserver, which is great! Now let’s do one more thing.

Currently we only use the localhost:3000 path. A bigger application has many endpoints. If you enter localhost:3000/me in the browser, you will get the familiar Cannot GET /me message, saying that the path is not defined yet. The server doesn’t know what to do when this endpoint is hit.

It’ll make sense to add a custom error message later, but for now let’s just add some response to this path.

Somewhere after PORT is declared, declare a variable called name and assign it your name as a string:

const PORT = 3000;
const name = YOUR_NAME_AS_A_STRING;

After the first app.get, we can define the path for /me:

app.get('/', (req, res) => {
  res.send('Response from server');
});

app.get('/me', (req, res) => {
  res.send(`My name is ${ name } and I'm saying hi from the server`);
});

Restart the server and go to localhost:3000. You will see “Response from the server”. Now add /me to the end of the URL in the browser’s address bar and you should see “My name is and I'm saying hi from the server".

Make sure you use backticks inside send else you won’t see your name.

Now we have an endpoint which sends us a response other than the default message when it’s hit. Great!

When a wrong endpoint is hit

As we have seen if we try to access a route which no response is configured to, we will get a Cannot GET /... error. It’s clear that we can’t cover each possible endpoint as the number of options is converging to infinity.

Sure, we can prepare for some scenarios and brainstorm e.g. all typos related to our paths, and cover those as well.

But what can we do with the rest?

The wildcard solution comes to the rescue:

app.get('/', (req, res) => {
  res.send('Response from server');
});

app.get('/me', (req, res) => {
  res.send(`My name is ${ name } and I'm saying hi from the server`);
});

app.get('*', (req, res) => {
  res.send('404 error - This page doesn\'t exist.');
});

The * character represents all other endpoints and we can create a custom message if one of these is hit. For example, if we enter localhost:3000/jason_bourne in the address bar after the server has been restarted, we will receive the “404 error - This page doesn’t exist.” message. Note that I had to escape the ' character inside doesn\'t because I used single quotes for the message.

Conclusion

We are done for this post and have covered some of the basics. In the next part I will talk about status codes and how to add them to the response object. I’ll also mention some other routing options.

I hope to see you again next time!