How to Set up an Express.js Server in Node.js
In this tutorial, you’ll learn how to start a basic HTTP server in Node.js with a few lines of code. Express allows us to get to “Hello World” with a server quickly. We’ll create a basic server with a single route, create a middleware to log requests that we receive, as well as start our server listening on for requests on our localhost. Creating middleware and route handlers are the foundation of any server created with Express and will help you understand how to get started creating your own servers.
By the end of this tutorial, you should be able to:
- Learn what Express Server is in Node.js
- Build a simple Node Express app
- Create routes with Express in Node
- Create logging middleware that runs on every request
This tutorial is part 2 of 7 tutorials that walk through using Express.js to create an API proxy server.
Goal
In this tutorial, you’ll learn how to create a basic Express server and test route in Node and a simple logging middleware that runs for every request made to the server.
Prerequisites
- What Is the Express Node.js Framework?
- Express Middleware in Node.js
- How to Add a Route to an Express Server in Node.js
Watch: How to Set up an Express Server
First we need to create a project folder, install our dependencies, and create an index.js file.
mkdir hello-express
cd hello-express
npm init -y
npm i express
npm i -D nodemon
touch index.js
You should now have a package.json, package-lock.json, and index.js file in your directory. Verify this by listing the files:
ls -la
We installed nodemon
as a development dependency so we can restart our server each time we save changes to scripts within the project’s directory.
Let’s also create an npm script to run the server using nodemon during development. Open your package.json file and add the dev script:
{ "name": "hello-express", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" }, "devDependencies": { "nodemon": "^2.0.2" }}
Open index.js and we’ll create an Express app and start the server listening on port 3000
.
const express = require("express");const PORT = 3000;
const app = express();
app.listen(PORT, () => console.log("Server is listening on port " + PORT));
In this step we required express
and created a new Express app by calling express()
. Then we started the server with app.listen()
and passed in a port for it to listen on. To learn more about app.listen()
, see the Express API reference.
At this point our server won’t do anything at all! We need to add a route before we can access the server. Let’s create a middleware that listens to GET requests on the route /test
and responds with JSON.
const express = require("express");const PORT = 3000;
const app = express();
app.get("/test", (req, res) => { res.json({ ok: true });});
app.listen(PORT, () => console.log("Server is listening on port " + PORT));
Go ahead and run the application using
npm run dev
Then open a browser to localhost:3000/test. You should see {ok: true}
output on the page. Congrats! We have a server running with a test route.
To stop nodemon, press CTRL+C
.
Let’s create one more route, which will accept a dynamic parameter as part of the URL. We can read this parameter in our route handler, and use it to respond with a personal message.
Add a new route handler at the route /greet/:name
. Putting a :
before the name part of the URL string allows us to later read whatever was put there from the req.params
object.
This allows you to pass dynamic information into your URL, which can be useful when passing IDs or other dynamic data to your API.
const express = require("express");const PORT = 3000;
const app = express();
app.get("/test", (req, res) => { res.json({ ok: true });});
app.get("/greet/:name", (req, res) => { res.json({ greeting: `Hello ${req.params.name}!` });});
app.listen(PORT, () => console.log("Server is listening on port " + PORT));
If you visit localhost:3000/greet/world you should see {greeting: "Hello world!"}
in the browser.
Next we are going to create a simple middleware to log requests that the server receives. Right now we are just going to be logging them to the console.
To create a middleware, we create a function that accepts req, res, next
as arguments. The argument next
is a special function that passes control to the next registered middleware, if one exists. Since the middleware doesn’t end the request response cycle, we need to call next
once our middleware is done to invoke the next middleware. Otherwise, the request will hang and never finish.
To run the middleware for all requests the server gets, we can register it by passing the function into app.use
.
We are going to log the UNIX time (in milliseconds), the HTTP method we received a request for, and the url that was requested.
const express = require("express");const PORT = 3000;
const app = express();
function logger(req, res, next) { console.log(`[${Date.now()}] ${req.method} ${req.url}`);}
app.use(logger);
app.get("/test", (req, res) => { res.json({ ok: true });});
app.get("/greet/:name", (req, res) => { res.json({ greeting: `Hello ${req.params.name}!` });});
app.listen(PORT, () => console.log("Server is listening on port " + PORT));
Load the page in your browser and look at your console. Hmm, not seeing anything, right?
That’s because we left out an important part! In the above code we never called next
, so the middleware will hang, and our request never makes it to our route handler. This is a really common mistake when writing Express middleware. Make sure that you call next()
when a middleware has completed.
Let’s fix the code to call next()
:
const express = require("express");const PORT = 3000;
const app = express();
function logger(req, res, next) { console.log(`[${Date.now()}] ${req.method} ${req.url}`); next();}
app.use(logger);
app.get("/test", (req, res) => { res.json({ ok: true });});
app.get("/greet/:name", (req, res) => { res.json({ greeting: `Hello ${req.params.name}!` });});
app.listen(PORT, () => console.log("Server is listening on port " + PORT));
With that done, you should be able to see the console.log
output to your terminal when you reload your browser. Our middleware is running every time a request is made to the server.
Recap
In this tutorial we created a basic Express server. We created two route handlers, one of which accepts a dynamic parameter in the URL which we can use in our route handler. We also created a simple logging middleware that runs for every request made to the server. These are the basic necessities to get started building an API server with Express.
Keep going with the next tutorial in this set: Organize Your Node.js Code into Modules.
Further your understanding
- How could you uniquely identify each request that comes through the server? What could we add to the logging middleware in order to associate a unique ID with each request?
- What if you only wanted to log requests that came to a specific route? How would you change the route handler to also run the logging middleware?
- If we wanted to run middleware after our route handlers, how could we tell Express to trigger the next middleware?
Additional resources
- Express Hello World Example (expressjs.com)
- Express Routing Documentation (expressjs.com)
- Express Middleware Guide (expressjs.com)