Skip to content

Express.js Explained – Simplify HTTP Request Handling in Node

Express.js is a web framework that simplifies server-side HTTP request handling in Node.js. It extends Node’s HTTP module with built-in features such as routing and middleware, helping developers to build web applications and APIs efficiently without repetitive code.

This guide explains the purpose of Express.js by guiding you through a basic application setup. To begin, let’s ensure your system is ready for the steps ahead.

Make sure your system has Node.js 18 (or greater).

Use the mkdir command to create a new project directory:

Terminal window
mkdir codesweetly-expressjs-app-001

Next, navigate to your project directory using the command line.

Terminal window
cd path/to/codesweetly-expressjs-app-001

Once you’re in the project folder, use NPM to create a package.json file.

Terminal window
npm init -y

Next, open the package.json file and delete the main field.

Configure the Project as an ES Module Application

Section titled “Configure the Project as an ES Module Application”

This guide uses ES Modules in all JavaScript files, so update the type field in your project’s package.json file to module.

package.json
{
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"type": "module"
}

Express.js provides methods such as app.get(), res.send(), and res.json() to simplify handling web requests. The following steps demonstrate how to install and use Express in a basic Node.js application.

Terminal window
npm install express

Create a file to start the server and listen for browser connections.

Terminal window
touch index.js

3. Use Express.js to configure the project’s Node.js web server

Section titled “3. Use Express.js to configure the project’s Node.js web server”

Open the new JavaScript file and use Express.js to set up a web server:

index.js
// Add the Express module:
import express from "express";
// Create a new Express application instance:
const app = express();
// Set the port number where the server will run and listen for requests:
const port = 3000;
// Create a route handler for GET requests to the "/" path:
app.get("/", (req, res) => res.send("Hello, world!"));
// Run the server on the specified port:
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

Here’s what the code above does:

  • Create an Express application instance to access Express APIs, such as routers and middleware, which simplifies HTTP request handling in Node.js.
  • Use Express’s app.get() method to define how the server handles HTTP GET requests to the / route.
  • Use Express’s res.send() method to send an HTTP response and automatically set the appropriate headers based on the data type provided.
  • Use Express’s app.listen() method to start the Node.js HTTP server on a specific port and execute a callback when the server begins listening for client requests.

The node filename.extension command is a universal CLI tool for running all Node.js scripts, including those using Express.js to handle HTTP requests.

Terminal window
node index.js

While you can use Node’s native HTTP API to handle web requests, it requires manual configuration, such as inspecting each request’s method and URL, setting response headers, and converting objects to JSON.

Express abstracts repetitive request-handling logic into declarative methods, simplifying Node.js web server development.

Below are two examples comparing Node.js web server code written with the native HTTP module and with Express methods.

Example 1: Using raw Node.js to handle web requests

Section titled “Example 1: Using raw Node.js to handle web requests”

The following web server uses only Node’s built-in HTTP module to handle routes for the home page (/), books page (/books), and unavailable pages (404 error).

index.js
import { createServer } from "node:http";
const port = 3000;
const server = createServer((req, res) => {
if (req.method === "GET" && req.url === "/") {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Welcome to the homepage!");
} else if (req.method === "GET" && req.url === "/books") {
const books = [
{ id: 1, name: "Code React Sweetly" },
{ id: 2, name: "Creating NPM Package" },
];
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(books));
} else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Page not found");
}
});
server.listen(port, "localhost", () => {
console.log(`Raw Node server running at http://localhost:${port}`);
});

The snippet above uses Node’s native http module to build a web server that accepts and responds to browser connections. With raw Node.js, you must manually handle the following for each route:

  • Routing to the correct endpoint: if (req.method === "..." && req.url === "...")
  • Response header configuration: res.writeHead(...)
  • JSON formatting: JSON.stringify(...)

Now, let’s see how to build the same web server using Express.

Example 2: Using Express.js to handle web requests

Section titled “Example 2: Using Express.js to handle web requests”

The following web server uses Express methods to handle routes for the home page (/), books page (/books), and unavailable pages (404 error).

index.js
import express from "express";
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Welcome to the homepage!");
});
app.get("/books", (req, res) => {
const books = [
{ id: 1, name: "Code React Sweetly" },
{ id: 2, name: "Creating NPM Package" },
];
res.json(books);
});
app.use((req, res) => {
res.status(404).send("Page not found");
});
app.listen(port, "localhost", () => {
console.log(`Express server running at http://localhost:${port}`);
});

The snippet above uses Express.js to build a web server that accepts and responds to browser connections. Express simplifies the following tasks:

  • Routing logic: Express.js provides simple route declarations like app.get(), app.post(), and app.delete(), eliminating the need for complex conditional logic to check req.url and req.method for each route.
  • Response header configuration: Express automatically sets response headers and status codes with the argument to res.send(), eliminating the need to manually configure res.writeHead(...) for each endpoint.
  • JSON formatting: Express’s res.json() method automatically converts JavaScript objects into valid JSON responses, handling serialization and headers for you.

Important Stuff to Know About Creating Express.js Web Servers in Node.js

Section titled “Important Stuff to Know About Creating Express.js Web Servers in Node.js”

Keep the following key points in mind when creating Express.js servers in your Node.js project.

Most Express.js developers call app.listen() last

Section titled “Most Express.js developers call app.listen() last”

It’s common to call app.listen() last in an Express.js app. This way, all your routes, middleware, and error handlers are set up before the server starts listening for requests.

You can set the port number using environment variables

Section titled “You can set the port number using environment variables”

The port variable is usually written as follows when defined in an environment variable:

const port = process.env.PORT || 3000;

The above snippet instructs Node to use the port environment variable value, or default to 3000 if it’s not set. So, executing the following command in the terminal will set the port to 8000.

Terminal window
PORT=8000 node index.js

Here are some common response methods you’ll use in Express.js:

  • res.send(): Send an HTTP response to the client and automatically set the appropriate response headers based on the data type provided as the method’s argument.
  • res.json(): Send JSON responses to the client and automatically set the response’s Content-Type header to application/json.
  • res.redirect(): Redirect the client’s request to a different URL.
  • res.render(): Render a template engine’s view and send the resulting HTML string to the client.
  • res.status(): Set the response’s HTTP status code without ending the request-response cycle. You can chain other response methods to it, for example, res.status(404).send("404 Error: Page not found"). This method is not needed if the status code is 200 (the default).
  • res.end(): End the request-response cycle without sending any data to the client.

Express’s response methods do not terminate the HTTP request handler’s execution

Section titled “Express’s response methods do not terminate the HTTP request handler’s execution”

While response methods like res.send() close the HTTP request-response cycle, they do not end the execution of the route handler function.

Here’s an example:

app.get("/", (req, res) => {
// This sends a text response to the client and ends the request-response cycle, but does not end the route handler's execution:
res.send("Hello, client!");
// This logs the string to the console because the function is still running:
console.log("Hello, devs!");
// This will cause an error because the request-response cycle is closed, so you cannot send additional responses to the client during the callback's execution:
res.send("Hello, client again!");
});

The console.log() statement in the example above works because the request handler is still running. The res.send("Hello, client!") line only ends further HTTP responses; it does not stop the callback’s execution.