Building Web Servers with Express: The Backbone of the Web
Express is the most popular web framework for Node.js. It is "unopinionated," meaning it gives you the minimal tools necessary to build a server without forcing a specific file structure or database. From simple landing pages to massive APIs used by companies like Netflix and Uber, Express is the industry standard for server-side JavaScript.
This chapter covers the Request-Response lifecycle, the power of Middleware, and how to build secure, scalable RESTful APIs.
Why This Topic Matters
Building a server is how you turn a local script into a global service. Mastering Express allows you to:
- Handle HTTP Traffic: Understand how browsers and servers communicate using GET, POST, PUT, and DELETE.
- Create RESTful APIs: Build the back-end for mobile apps and modern front-end frameworks like React and Next.js.
- Process User Data: Receive information from forms, files, and JSON payloads safely.
- Scale Logic: Use middleware to handle authentication, logging, and error handling in a centralized way.
The Request-Response Lifecycle
Every time you visit a URL or click a button, a "Request" is sent to the server, and the server sends back a "Response."
Basic Routing
Routes define which code runs based on the URL and the HTTP Method.
app.get("/users", (req, res) => {
res.json({ message: "List of users" });
});
Middleware: The "Chain of Command"
Middleware functions are functions that have access to the request (req) and response (res) objects. They can execute code, modify the request, or end the cycle.
The next() Function: Middleware must call next() to pass control to the next function in the chain, otherwise the request will "hang" forever.
// Built-in middleware to parse JSON
app.use(express.json());
// Custom logging middleware
app.use((req, res, next) => {
console.log(`${req.method} request to ${req.url}`);
next(); // Pass to the actual route handler
});
Dynamic Routing: Params and Queries
Modern APIs often need to handle variable data in the URL.
1. Route Parameters (req.params)
Used for identifying specific resources.
- URL:
/users/42 - Route:
/users/:id→req.params.idis"42"
2. Query Parameters (req.query)
Used for filtering or sorting.
- URL:
/search?term=javascript - Route:
/search→req.query.termis"javascript"
Handling Data with POST and JSON
To receive data from a client (like a login form), you use the POST method.
app.post("/login", (req, res) => {
const { username, password } = req.body;
if (username === "admin" && password === "123") {
res.status(200).json({ success: true });
} else {
res.status(401).json({ error: "Invalid credentials" });
}
});
Error Handling: The Safety Net
Express has a special type of middleware for errors that takes four arguments: (err, req, res, next).
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: "Something went wrong!" });
});
Common Mistakes & Pitfalls
- Forgetting
express.json(): Trying to accessreq.bodyand gettingundefined. - Multiple Responses: Trying to call
res.send()twice in one route. (The second one will crash the server). - Hanging Requests: Forgetting to call
next()in a middleware orres.send()in a route. - Security Risks: Exposing sensitive file paths or database errors in the production response.
Mini Exercises
- Hello Express: Build a server that listens on port 4000 and returns "Welcome to my API" on the root
/path. - Dynamic Profile: Create a route
/profile/:usernamethat returns a message saying "Hello, [username]". - JSON Echo: Create a POST route
/echothat returns whatever JSON object was sent in the request body. - Logging Middleware: Write a middleware that logs the timestamp of every request.
- Status Codes: Create a route
/secretthat returns a403 Forbiddenstatus code if a query parameterkeyis not equal to "topsecret".
Review Questions
- What is the difference between
req.paramsandreq.query? - Why is the
next()function important in middleware? - What is the purpose of
app.use(express.json())? - How do you send a specific HTTP status code (like 404) in Express?
- What is the difference between
res.send()andres.json()?
Reference Checklist
- I can create a basic Express server and listen on a port.
- I understand how to define GET and POST routes.
- I can use middleware to log requests and parse JSON.
- I know how to extract data from
req.paramsandreq.query. - I can send JSON responses with appropriate status codes.
- I understand how to handle errors using specialized middleware.