Express Basics
'Express' is the most widely used web framework for Node.js. It lets you describe HTTP server construction, routing, and middleware management concisely, and is used as the foundation for REST (Representational State Transfer) APIs and web applications.
Installation
Express is installed via npm. Run the following commands in your project directory.
mkdir my-app && cd my-app npm init -y npm install express
Main Methods
| Method / Property | Description |
|---|---|
| express() | Creates an Express application instance. |
| app.get(path, handler) | Defines a route for GET requests. |
| app.post(path, handler) | Defines a route for POST requests. |
| app.put(path, handler) | Defines a route for PUT requests. |
| app.delete(path, handler) | Defines a route for DELETE requests. |
| app.use(path, middleware) | Registers middleware. Omitting path applies it to all requests. |
| app.listen(port, callback) | Starts an HTTP server on the specified port. |
| req.params | Object containing URL parameters (e.g., :id). |
| req.query | Object containing query parameters (e.g., ?key=value). |
| req.body | Object containing the request body. Requires the express.json() middleware. |
| res.send(data) | Sends a response. Accepts strings, Buffers, etc. |
| res.json(obj) | Converts an object to JSON and sends it as a response. |
| res.status(code) | Sets the HTTP status code. Used with method chaining. |
| res.redirect(url) | Redirects to the specified URL. |
| express.static(root) | A built-in middleware for serving static files. |
Hello World
The minimal Express setup. Create an app with express(), define routes, then start the server with listen().
app.js
var express = require('express');
var app = express();
// GET request: define the response when / is accessed
app.get('/', function(req, res) {
res.send('El Psy Kongroo — Welcome to the lab!');
});
// Start the server on port 3000
app.listen(3000, function() {
console.log('Server started: http://localhost:3000/');
});
node app.js Server started: http://localhost:3000/
curl http://localhost:3000/ El Psy Kongroo — Welcome to the lab!
GET / POST / PUT / DELETE Routing
In Express, routes are defined using methods corresponding to HTTP methods. The following demonstrates a basic REST (Representational State Transfer) API structure.
routes.js
var express = require('express');
var app = express();
// Middleware to parse request body as JSON
app.use(express.json());
// Lab member data
var members = [
{ id: 1, name: 'Okabe Rintaro', role: 'Mad scientist' },
{ id: 2, name: 'Makise Kurisu', role: 'Genius scientist' },
{ id: 3, name: 'Shiina Mayuri', role: "Okabe's childhood friend" },
];
// GET: retrieve the list of lab members
app.get('/members', function(req, res) {
res.json(members);
});
// GET: retrieve a specific lab member by ID
app.get('/members/:id', function(req, res) {
var id = parseInt(req.params.id, 10);
var member = members.find(function(m) { return m.id === id; });
if (!member) {
return res.status(404).json({ error: 'Lab member not found' });
}
res.json(member);
});
// POST: add a new lab member
app.post('/members', function(req, res) {
var newMember = {
id: members.length + 1,
name: req.body.name,
role: req.body.role,
};
members.push(newMember);
res.status(201).json(newMember);
});
// PUT: update a lab member's information
app.put('/members/:id', function(req, res) {
var id = parseInt(req.params.id, 10);
var member = members.find(function(m) { return m.id === id; });
if (!member) {
return res.status(404).json({ error: 'Lab member not found' });
}
member.name = req.body.name || member.name;
member.role = req.body.role || member.role;
res.json(member);
});
// DELETE: remove a lab member
app.delete('/members/:id', function(req, res) {
var id = parseInt(req.params.id, 10);
var index = members.findIndex(function(m) { return m.id === id; });
if (index === -1) {
return res.status(404).json({ error: 'Lab member not found' });
}
var removed = members.splice(index, 1)[0];
res.json({ message: removed.name + ' was removed' });
});
app.listen(3000, function() {
console.log('Server started: http://localhost:3000/');
});
node routes.js Server started: http://localhost:3000/
curl http://localhost:3000/members
[{"id":1,"name":"Okabe Rintaro","role":"Mad scientist"},...]
curl http://localhost:3000/members/2
{"id":2,"name":"Makise Kurisu","role":"Genius scientist"}
curl -X POST -H "Content-Type: application/json" -d '{"name":"Hashida Itaru","role":"Super hacker"}' http://localhost:3000/members
{"id":4,"name":"Hashida Itaru","role":"Super hacker"}
curl -X DELETE http://localhost:3000/members/4
{"message":"Hashida Itaru was removed"}
Registering Middleware
Register middleware with app.use(). Middleware is processing inserted between a request and response, handling logging, authentication, body parsing, and more. Calling next() advances to the next step.
middleware.js
var express = require('express');
var app = express();
// Middleware to output access logs (applied to all requests)
app.use(function(req, res, next) {
var timestamp = new Date().toISOString();
console.log('[' + timestamp + '] ' + req.method + ' ' + req.url);
next(); // advance to next middleware / route
});
// Middleware to check authentication when accessing /secure
app.use('/secure', function(req, res, next) {
var token = req.headers['x-lab-token'];
if (token !== 'tutturu') {
return res.status(401).json({ error: 'Authentication failed' });
}
next();
});
app.get('/', function(req, res) {
res.send('Welcome to the lab!');
});
app.get('/secure/data', function(req, res) {
res.json({ secret: 'Time machine blueprints', owner: 'Amane Suzuha' });
});
app.listen(3000, function() {
console.log('Server started: http://localhost:3000/');
});
node middleware.js Server started: http://localhost:3000/
curl http://localhost:3000/secure/data
{"error":"Authentication failed"}
curl -H "x-lab-token: tutturu" http://localhost:3000/secure/data
{"secret":"Time machine blueprints","owner":"Amane Suzuha"}
curl http://localhost:3000/
Welcome to the lab!
Serving Static Files
Using express.static(), you can serve files in a specified directory as static files. Use it for serving HTML, CSS, images, and so on.
static_server.js
var express = require('express');
var path = require('path');
var app = express();
// Specify the public directory as the source of static files
// /public/index.html is accessible at http://localhost:3000/index.html
app.use(express.static(path.join(__dirname, 'public')));
// Another directory can also be served under the /assets path
app.use('/assets', express.static(path.join(__dirname, 'static')));
app.listen(3000, function() {
console.log('Server started: http://localhost:3000/');
});
node static_server.js Server started: http://localhost:3000/
Template Engine (EJS)
Express supports multiple template engines including EJS, Pug, and Handlebars. Specify the engine with app.set('view engine', 'ejs') and render templates with res.render().
npm install ejs
views/index.ejs
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
<h1><%= title %></h1>
<ul>
<% members.forEach(function(m) { %>
<li><%= m.name %> — <%= m.role %></li>
<% }); %>
</ul>
</body>
</html>
ejs_app.js
var express = require('express');
var app = express();
// Specify EJS as the template engine
app.set('view engine', 'ejs');
// Directory where template files are stored (default is views/)
app.set('views', './views');
var members = [
{ name: 'Okabe Rintaro', role: 'Mad scientist' },
{ name: 'Makise Kurisu', role: 'Genius scientist' },
{ name: 'Shiina Mayuri', role: "Okabe's childhood friend" },
];
app.get('/', function(req, res) {
// Specify data to pass to the template as the second argument
res.render('index', { title: 'Lab Member List', members: members });
});
app.listen(3000, function() {
console.log('Server started: http://localhost:3000/');
});
node ejs_app.js Server started: http://localhost:3000/
Summary
Express can define routes for each HTTP method using app.get(), app.post(), app.put(), and app.delete(). Parsing the request body with express.json() and returning a JSON response with res.json() is the basic pattern for REST APIs.
Middleware registered with app.use() processes requests in registration order. Forgetting to call next() stops the request there, so care is needed. Static file serving can be set up easily with express.static().
Template engines can be chosen from EJS, Pug, Handlebars, and more. Specify with app.set('view engine', ...) and generate HTML with res.render(). When used as an API server, no template engine is needed — res.json() alone suffices.
Common Mistakes
Common Mistake 1: Forgetting express.json() middleware causes req.body to be undefined
To receive a request body in POST or PUT requests, express.json() must be registered as middleware. Without it, req.body is undefined.
// NG: express.json() is not registered
var express = require('express');
var app = express();
app.post('/members', function(req, res) {
console.log(req.body); // becomes undefined
res.json({ received: req.body });
});
Correct approach:
// OK: Register express.json() before defining routes
var express = require('express');
var app = express();
app.use(express.json()); // register first
app.post('/members', function(req, res) {
console.log(req.body); // { name: 'Okabe Rintaro', role: '...' }
res.json({ received: req.body });
});
Common Mistake 2: Port conflict in app.listen (EADDRINUSE error)
If the specified port is already being used by another process, an EADDRINUSE error occurs and the server cannot start. Specify a different port number or stop the process using that port.
// Error example:
// Error: listen EADDRINUSE: address already in use :::3000
app.listen(3000, function() {
console.log('Server started');
});
// If port 3000 is already in use, this callback is never reached
How to handle it:
// OK: Use a different port
app.listen(3001, function() {
console.log('Server started on port 3001');
});
// Or switch ports via environment variable
var PORT = process.env.PORT || 3000;
app.listen(PORT, function() {
console.log('Server started on port ' + PORT);
});
Common Mistake 3: Route definition order — /new matches /:id when defined after it
Express evaluates routes from top to bottom in the order they are defined. If /:id is defined first, /new will match /:id and the string "new" is treated as the id. Specific paths should be defined before dynamic paths.
// NG: Defining /:id first causes /new to match /:id
app.get('/members/:id', function(req, res) {
res.json({ id: req.params.id }); // /members/new also comes here (id = 'new')
});
app.get('/members/new', function(req, res) {
res.json({ form: 'New registration form' }); // never reached
});
Correct approach:
// OK: Define specific paths first
app.get('/members/new', function(req, res) {
res.json({ form: 'New registration form' }); // /members/new correctly comes here
});
app.get('/members/:id', function(req, res) {
res.json({ id: req.params.id }); // /members/1 etc. come here
});
If you find any errors or copyright issues, please contact us.