Creating Routes and Handling Requests with Express

Node.js has a built-in HTTP module, but writing servers with it is verbose. Express.js simplifies everything. It handles routing, request parsing, and response sending with clean, simple code.
What is Express?
Express is a lightweight web framework for Node.js. It makes building web applications easier by providing helpful features for routing, middleware, and responses.
Without Express, here's a basic Node.js server:
import http from 'http';
const server = http.createServer((req, res) => {
if (req.url === '/' && req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Home page');
} else if (req.url === '/about' && req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('About page');
} else {
res.statusCode = 404;
res.end('Not found');
}
});
server.listen(3000);
This gets messy quickly. With multiple routes, you'd have many if-else statements.
With Express, the same thing is much simpler:
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Home page');
});
app.get('/about', (req, res) => {
res.send('About page');
});
app.listen(3000);
Much cleaner. Express handles the complexity.
Setting Up Express
First, create a project and install Express:
npm init -y
npm install express
Create a file called server.js:
import express from 'express';
const app = express();
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Run it:
node server.js
You have a running server. It doesn't do anything yet, but it's listening on port 3000.
Understanding Routes
A route is a combination of:
HTTP method (GET, POST, PUT, DELETE, etc.)
URL path (/home, /users, /posts/123, etc.)
Handler function (what to do when this route is called)
The basic structure is:
app.METHOD(PATH, HANDLER);
For example:
app.get('/home', (req, res) => {
res.send('This is the home page');
});
This means: "When someone sends a GET request to /home, execute this function."
GET Requests
GET requests fetch data. They're read-only and don't change anything.
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Welcome to the home page');
});
app.get('/about', (req, res) => {
res.send('This is the about page');
});
app.get('/contact', (req, res) => {
res.send('Contact us at info@example.com');
});
app.listen(3000, () => {
console.log('Server running');
});
Now visit:
http://localhost:3000/→ "Welcome to the home page"http://localhost:3000/about→ "This is the about page"http://localhost:3000/contact→ "Contact us at..."
POST Requests
POST requests send data to the server. They typically create new resources.
For this, you need to parse incoming data. Express provides middleware for this:
import express from 'express';
const app = express();
// Parse JSON data
app.use(express.json());
app.get('/', (req, res) => {
res.send('GET request received');
});
app.post('/submit', (req, res) => {
const { name, email } = req.body;
res.send(`Thank you, \({name}. We'll email \){email}`);
});
app.listen(3000, () => {
console.log('Server running');
});
When someone sends a POST request to /submit with JSON data, Express parses it and stores it in req.body.
To test this, you'd need a tool like Postman or curl:
curl -X POST http://localhost:3000/submit \
-H "Content-Type: application/json" \
-d '{"name":"John","email":"john@example.com"}'
Response: "Thank you, John. We'll email john@example.com"
URL Parameters
Routes can have dynamic parts. Parameters start with a colon:
import express from 'express';
const app = express();
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`Getting user ${userId}`);
});
app.get('/posts/:postId/comments/:commentId', (req, res) => {
const { postId, commentId } = req.params;
res.send(`Comment \({commentId} on post \){postId}`);
});
app.listen(3000);
Examples:
GET /users/123→ "Getting user 123"GET /posts/456/comments/789→ "Comment 789 on post 456"
Query Parameters
Query parameters come after a question mark and are optional:
import express from 'express';
const app = express();
app.get('/search', (req, res) => {
const query = req.query.q;
const limit = req.query.limit;
res.send(`Searching for "\({query}", limit \){limit}`);
});
app.listen(3000);
Examples:
GET /search?q=javascript→ "Searching for 'javascript', limit undefined"GET /search?q=node&limit=10→ "Searching for 'node', limit 10"
Response Methods
Express provides several ways to send responses:
import express from 'express';
const app = express();
// Send plain text
app.get('/text', (req, res) => {
res.send('This is plain text');
});
// Send JSON
app.get('/json', (req, res) => {
res.json({ message: 'This is JSON', status: 'success' });
});
// Send HTML
app.get('/html', (req, res) => {
res.send('<h1>This is HTML</h1>');
});
// Send with status code
app.get('/error', (req, res) => {
res.status(404).send('Not found');
});
// Redirect
app.get('/old-path', (req, res) => {
res.redirect('/new-path');
});
app.listen(3000);
Handling All HTTP Methods
Express supports all standard HTTP methods:
import express from 'express';
const app = express();
app.use(express.json());
app.get('/users', (req, res) => {
res.json({ message: 'Get all users' });
});
app.post('/users', (req, res) => {
res.json({ message: 'Create new user' });
});
app.put('/users/:id', (req, res) => {
res.json({ message: `Update user ${req.params.id}` });
});
app.delete('/users/:id', (req, res) => {
res.json({ message: `Delete user ${req.params.id}` });
});
app.listen(3000);
Handling 404 Errors
When a route doesn't exist, Express returns a 404 error by default. You can customize this:
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Home');
});
// Catch all unmatched routes
app.use((req, res) => {
res.status(404).send('Page not found');
});
app.listen(3000);
The order matters. This "catch-all" route must be last, otherwise it will intercept all requests.
A Complete Example
Let's build a simple blog API:
import express from 'express';
const app = express();
app.use(express.json());
// Sample data
let posts = [
{ id: 1, title: 'First Post', content: 'Hello world' },
{ id: 2, title: 'Second Post', content: 'Another post' }
];
// GET all posts
app.get('/posts', (req, res) => {
res.json(posts);
});
// GET single post
app.get('/posts/:id', (req, res) => {
const post = posts.find(p => p.id === parseInt(req.params.id));
if (!post) {
return res.status(404).send('Post not found');
}
res.json(post);
});
// CREATE new post
app.post('/posts', (req, res) => {
const newPost = {
id: posts.length + 1,
title: req.body.title,
content: req.body.content
};
posts.push(newPost);
res.status(201).json(newPost);
});
// UPDATE post
app.put('/posts/:id', (req, res) => {
const post = posts.find(p => p.id === parseInt(req.params.id));
if (!post) {
return res.status(404).send('Post not found');
}
post.title = req.body.title || post.title;
post.content = req.body.content || post.content;
res.json(post);
});
// DELETE post
app.delete('/posts/:id', (req, res) => {
const index = posts.findIndex(p => p.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).send('Post not found');
}
const deleted = posts.splice(index, 1);
res.json(deleted);
});
app.listen(3000, () => {
console.log('Blog API running on port 3000');
});
This simple API lets you create, read, update, and delete posts.
Common Mistakes
Mistake 1: Forgetting middleware
// Wrong - won't parse JSON
app.post('/data', (req, res) => {
console.log(req.body); // undefined
});
// Correct
app.use(express.json());
app.post('/data', (req, res) => {
console.log(req.body); // has data
});
Mistake 2: Forgetting to return after sending response
app.get('/users/:id', (req, res) => {
if (!id) {
res.status(400).send('Invalid ID');
// BUG: continues executing below
}
res.send('User data');
});
// Better
app.get('/users/:id', (req, res) => {
if (!id) {
return res.status(400).send('Invalid ID');
}
res.send('User data');
});
Key Takeaways
Express simplifies building web servers with Node.js
Routes combine HTTP method, path, and handler function
GET requests fetch data, POST requests send data
URL parameters (
:id) capture dynamic valuesQuery parameters (
?key=value) pass optional filtersMiddleware processes requests before they reach handlers
Always return after sending a response
Use appropriate HTTP status codes
Express makes building web applications enjoyable. These fundamentals are the foundation for all Express applications.




