Creating Routes and Handling Requests with Express

What Express.js Is
Express.js is a lightweight framework built on top of Node.js’s built-in http module, giving developers a much simpler, cleaner way to build web servers — defining routes, handling requests, and sending responses without manually managing the low-level details Node's raw HTTP module leaves entirely up to you.
Node.js can build a server on its own — but Express is what most real-world Node applications actually use, because of exactly how much repetitive, error-prone work it removes.
Why Express Simplifies Node.js Development
The raw Node.js way
const http = require("http");
const server = http.createServer((req, res) => {
if (req.url === "/" && req.method === "GET") {
res.end("Home");
} else if (req.url === "/users" && req.method === "GET") {
res.end("Users list");
} else if (req.url === "/users" && req.method === "POST") {
res.statusCode = 201;
res.end("User created");
} else {
res.statusCode = 404;
res.end("Not found");
}
});
server.listen(3000);Every single route requires manually checking req.url and req.method, in an ever-growing chain of if/else if statements. This works, but it scales badly — a real application with dozens of routes becomes an unmanageable wall of manual conditionals.
The Express way
const express = require("express");
const app = express();
app.get("/", (req, res) => res.send("Home"));
app.get("/users", (req, res) => res.send("Users list"));
app.post("/users", (req, res) => res.status(201).send("User created"));
app.listen(3000);Same functionality, dramatically less code — Express handles matching the URL and method internally, letting you declare routes directly and clearly, instead of manually parsing every request yourself.

Creating Your First Express Server
npm install express
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello, Express!");
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});Breaking this down:
- require("express") — loads the Express library
- express() — creates an Express application
- app.get(...) — defines a route (covered next)
- app.listen(PORT, ...) — starts the server, listening for requests
Run it with node server.js, then visit http://localhost:3000 in a browser to see "Hello, Express!" displayed directly.

Handling GET Requests
GET requests retrieve data — the most common type of request, used every time a browser loads a page or fetches information.
app.get("/about", (req, res) => {
res.send("This is the about page.");
});
app.get("/users/:id", (req, res) => {
const userId = req.params.id;
res.send(`Fetching user with ID: ${userId}`);
});Each app.get(path, handler) call registers a route: when a GET request arrives matching that specific path, Express calls the matching handler function, passing in req (the request) and res (the response) — no manual URL comparison needed at all.
Handling POST Requests
POST requests send data to the server, typically to create something new.
app.use(express.json()); // needed to read JSON data sent in a request body
app.post("/users", (req, res) => {
const newUser = req.body; // the data the client sent
console.log("Creating user:", newUser);
res.status(201).send(`User ${newUser.name} created`);
});
express.json() is built-in middleware (covered in depth in this series's dedicated middleware article) that parses incoming JSON data and makes it available on req.body — without it, req.body would simply be undefined for JSON requests.

Sending Responses
Express provides several convenient ways to send a response back to the client.
Plain text or HTML
res.send("Hello!");JSON data
res.json({ id: 1, name: "Aarav" });Setting a status code
res.status(404).send("Not found");
res.status(201).json({ message: "Created successfully" });Combining status code and data (the common pattern)
app.post("/users", (req, res) => {
const newUser = { id: 1, name: req.body.name };
res.status(201).json(newUser);
});res.status(...) sets the HTTP status code, and can be chained directly with .send() or .json() to send both the status and the actual response body in one clean statement.

The Full Request → Response Flow

A complete, minimal example bringing it all together
const express = require("express");
const app = express();
app.use(express.json());
app.get("/", (req, res) => {
res.send("Welcome to the API");
});
app.get("/users/:id", (req, res) => {
res.json({ id: req.params.id, name: "Sample User" });
});
app.post("/users", (req, res) => {
const newUser = { id: 2, name: req.body.name };
res.status(201).json(newUser);
});
app.listen(3000, () => console.log("Server running on port 3000"));This small file already demonstrates the complete core pattern every Express application is built from: define routes for specific paths and methods, handle incoming data, and send an appropriate response — the exact same shape this article’s REST API design article (elsewhere in this series) builds on at a larger scale.
Final Takeaway
Express doesn’t do anything Node.js couldn’t technically do on its own — it removes the repetitive, error-prone work of manually parsing URLs and methods for every single route, replacing it with clear, declarative route definitions: app.get(), app.post(), and their siblings. GET retrieves data; POST sends it; res.send(), res.json(), and res.status() give you clean, direct control over exactly what goes back to the client. Once this basic request-to-response shape feels natural, it scales cleanly to real applications with dozens of routes — which is exactly why Express became the default starting point for so much of the Node.js ecosystem.
Frequently Asked Questions
Do I need express.json() for every route, or just POST routes?
> It only matters for routes that need to read JSON data from the request body — typically POST, PUT, or PATCH requests. It's harmless to include it globally with app.use(), even if some routes don't use it.
What’s the difference between res.send() and res.json()?
> res.send() can send plain text, HTML, or (if given an object) will automatically format it as JSON too. res.json() is more explicit — it's specifically intended for sending JSON data, and is generally the clearer, more intentional choice when you know you're sending structured data.
Can one route handle both GET and POST for the same path?
> Yes — you’d simply define both app.get("/path", ...) and app.post("/path", ...) separately; Express matches based on both the path and the HTTP method together, so they don't conflict.
Is raw Node.js ever a better choice than Express?
> For very small, simple scripts, or for learning exactly how HTTP servers work at a fundamental level, raw Node.js is a reasonable choice. For any real application with more than a couple of routes, Express’s cleaner routing and built-in conveniences save significant, genuinely error-prone repetitive work.
Creating Routes and Handling Requests with Express was originally published in Towards Dev on Medium, where people are continuing the conversation by highlighting and responding to this story.
Originally published by Mr Madhukar
Read the complete article on Medium with full formatting & reader responses.