Node.js: Express Basics
Last updated: 2026-08-26
1. From Native HTTP to Express
Alice spent three days writing an API using the native HTTP module, but the code was long and difficult to maintain—she had to manually parse URLs, write route matches by hand, and process the request body line by line. After switching to Express, she was able to implement the same functionality in just 30 lines of code, with clearly defined routes and automatically chained middleware, resulting in a 10-fold increase in maintenance efficiency.
Comparison of Native HTTP and Express Code
| Comparison | Native HTTP | Express |
|---|---|---|
| Route Definition | Manual if/else Match req.url |
Declarative app.get('/path', fn) |
| Request Body Parsing | Manually Listen for data/end Events and Build a Buffer |
express.json() Done in One Line |
| Response Sent | res.writeHead() + res.end() |
res.json() / res.send() |
| Static File | Manually read the file + set Content-Type | express.static('public') |
| Middleware | No built-in support | app.use() Pipeline-style composition |
| Code size (for equivalent functionality) | ~80 lines | ~30 lines |
- Express is the most popular web framework for Node.js; it abstracts the underlying details of the HTTP module.
- The declarative approach to routing makes the mapping between URLs and handlers immediately clear
- The middleware mechanism implements separation of concerns: logging, authentication, and parsing each perform their respective functions.
- Includes
json()andstatic()to meet the two most common API development needs - A vast ecosystem offers a wide range of third-party middleware that’s ready to use right out of the box
2. Installation and "Hello World"
▶ Example: (1) Initializing the Project and Installing Express
mkdir my-express-app && cd my-express-app
npm init -y
npm install express
▶ Example: (2) Minimal Hello World
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
node app.js
Simply visit http://localhost:3000 in your browser to view Hello World!.
▶ Example: Return a JSON response
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from Express!', status: 'ok' });
});
▶ Example: "Hello" with routing parameters
app.get('/hello/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
3. Routing Methods
Express Routing Methods Quick Reference
| Method | Purpose | Idempotency | Typical Scenarios |
|---|---|---|---|
app.get() |
Get Resources | Yes | View List/Details |
app.post() |
Create Resource | No | Submit Form/Add Record |
app.put() |
Full Update | Yes | Replace Entire Record |
app.delete() |
Delete Resource | Yes | Delete Record |
app.patch() |
Partial update | No | Modify individual fields |
app.all() |
Match all methods | — | General preprocessing |
▶ Example: (1) RESTful-style routing
app.get('/users', (req, res) => { res.json({ users: [] }); });
app.post('/users', (req, res) => { res.status(201).json({ created: true }); });
app.put('/users/:id', (req, res) => { res.json({ updated: req.params.id }); });
app.delete('/users/:id', (req, res) => { res.json({ deleted: req.params.id }); });
(2) Route Matching
- Exact match:
'/about'matches only/about - Parameter mapping:
'/users/:id'maps to/users/42, with the value determined byreq.params.id - Wildcard matching:
'/files/*'matches/files/a/b/c
▶ Example: Reading Query Parameters
app.get('/search', (req, res) => {
const { q, page = '1' } = req.query;
res.json({ keyword: q, page: Number(page) });
});
▶ Example: Multiple Route Parameters
app.get('/posts/:postId/comments/:commentId', (req, res) => {
res.json(req.params);
});
4. The Concept of Middleware
At the heart of Express’s design is the middleware pipeline—each request flows sequentially through a series of functions, each of which can read or modify the request and response, or terminate the request early.
flowchart LR A[Request Request] --> B[Middleware1<br/>Logging] B --> C[Middleware2<br/>JSONAnalysis] C --> D[Middleware3<br/>Authentication and Validation] D --> E[Route Handling<br/>Business Logic] E --> F[Response Response]
▶ Example: (1) app.use() to register middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next();
};
app.use(logger);
(2) Order of Middleware Execution
app.use()Execute in the order of registration; the position determines the logic- Calling
next()hands control over to the next middleware - If
next()is not called, the request will be suspended; you must send the response yourself.
▶ Example: Authentication Middleware
const auth = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(401).json({ error: 'No token' });
next();
};
app.use('/api', auth);
▶ Example: Error-handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
5. Built-in Middleware
List of Built-in Middleware
| Middleware | Purpose | Implementation | Common Configurations |
|---|---|---|---|
express.json() |
Parsing the JSON Request Body | app.use(express.json()) |
{ limit: '10kb' } |
express.urlencoded() |
Parsing URL-encoded request bodies | app.use(express.urlencoded({ extended: true })) |
{ extended: true/false } |
express.static() |
Hosting Static Files | app.use(express.static('public')) |
{ maxAge: '1d' } |
▶ Example: (1) Parsing the request body with express.json()
app.use(express.json());
app.post('/api/users', (req, res) => {
console.log(req.body);
res.json({ received: req.body });
});
(2) express.static() for serving static files
Assumed project structure:
my-express-app/
├── public/
│ ├── index.html
│ └── style.css
├── app.js
└── package.json
app.use(express.static('public'));
Visit http://localhost:3000/index.html to load static files directly.
▶ Example: Static Hosting with Multiple Directories
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
▶ Example: Limiting the size of a JSON request body
app.use(express.json({ limit: '100kb' }));
6. nodemon Hot Reload
nodemon vs. node comparison
| Comparison Item | node |
nodemon |
|---|---|---|
| After file changes | Manual restart | Automatic restart |
| Installation Method | Built-in | npm i -D nodemon |
| Startup Command | node app.js |
npx nodemon app.js |
| Production Environment | Applicable | Not Applicable |
| Watch Directory | None | Default: current directory; configurable |
▶ Example: (1) Installation and Use
npm install --save-dev nodemon
npx nodemon app.js
▶ Example: (2) Configuring Scripts in package.json
{
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js"
}
}
Use npm run dev (automatic reload) during development, and npm start (stable operation) in production.
▶ Example: Custom Monitoring Directory
npx nodemon --watch src --ext js,ets app.js
7. Comprehensive Example: Express API Application
Let’s tie together all the concepts covered so far and build a complete, small-scale API application from scratch.
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.static('public'));
let todos = [
{ id: 1, task: 'Learn Express', done: false },
{ id: 2, task: 'Build an API', done: false },
];
app.get('/api/todos', (req, res) => res.json(todos));
app.post('/api/todos', (req, res) => {
const todo = { id: todos.length + 1, ...req.body, done: false };
todos.push(todo);
res.status(201).json(todo);
});
app.put('/api/todos/:id', (req, res) => {
const idx = todos.findIndex(t => t.id === Number(req.params.id));
if (idx === -1) return res.status(404).json({ error: 'Not found' });
todos[idx] = { ...todos[idx], ...req.body };
res.json(todos[idx]);
});
app.delete('/api/todos/:id', (req, res) => {
todos = todos.filter(t => t.id !== Number(req.params.id));
res.json({ deleted: true });
});
app.listen(3000, () => console.log('API running at http://localhost:3000'));
Once it's up and running, you can access the static pages using a browser and use the API tool to perform CRUD operations on /api/todos.
- After installing Express, use
express.json()andexpress.static()to handle request body parsing and static hosting in a single line - RESTful Routing
GET/POST/PUT/DELETECovers the Full CRUD Cycle - During development, code changes made in conjunction with
nodemontake effect automatically; no manual restart is required.
❓ FAQ
app.use and app.get?app.use matches all request methods and is commonly used for middleware; app.get matches only GET requests and is used to define routes.app.use or app.get. Calling next() proceeds to the next middleware; if next() is not called, execution terminates.Q: Is Express the only option? A: No. Koa is lighter, Fastify is faster, and Hono supports edge computing, but Express has the most mature ecosystem and the most learning resources, making it the best choice for beginners.
Q: Does express.json() have to be called before the route? A: Yes, app.use(express.json()) must be written before the route; otherwise, req.body will become undefined, because middleware is executed in the order in which it is registered.
Q: What is the difference between 4.x and 5.x? A: Express 5.x removes deprecated APIs (such as app.del), improves route matching (with support for path-to-regexp v8), and makes some behaviors more asynchronous-friendly, but the core usage remains largely the same.
Q: How do I automatically restart the service? A: Install nodemon (npm i -D nodemon), start it with npx nodemon app.js, and it will automatically restart after the file is saved—which is very efficient during development.
Q: What is the difference between app.use and app.get? A: app.use matches all HTTP methods and matches the path prefix (/api matches /api/anything), while app.get matches only the GET method and requires an exact path match. The former is used for middleware, and the latter is used for routing.
Q: What does the extended option in express.urlencoded mean? A: extended: true uses the qs library for parsing (supports nested objects), extended: false uses the querystring library (does not support nested objects), and true is generally sufficient for form submissions.
📖 Summary
- 1 Core Concepts and Usage of Express, from Native HTTP to Express
- 2 Installation, Core Concepts, and Usage of "Hello World"
- 3 Core Concepts and Usage of Routing Methods
- 4 Core Concepts and Usage of Middleware
- 5 Core Concepts and Usage of Built-in Middleware
- 6 Core Concepts and Usage of Nodemon Hot Reload
- 7 Comprehensive Example: Core Concepts and Usage of an Express API Application
📝 Exercises
- Complete all the code examples in this lesson and make sure each one runs correctly.
- Modify the comprehensive example and add your own extensions
- Review the official documentation, identify 1–2 APIs not covered in this lesson, and write test code for them.
- Reflection: How would you apply what you’ve learned in this lesson to a real-world project?
- Try to combine what you’ve learned in this lesson with material from previous lessons to build a small project.