Express routing is the backbone of defining how your application responds to client requests at specific endpoints. It allows you to map HTTP methods (like GET, POST, PUT, DELETE) to specific URL paths, each handled by a dedicated function. For instance, app.get('/users', ...) would handle fetching user data, while app.post('/users', ...) would handle creating a new user. Each route handler receives req (request) and res (response) objects, enabling you to access incoming data and send back appropriate responses, forming the core interaction of your API.
Middleware functions are the power tools of Express. They are functions that execute in sequence before your final route handler. Each middleware has access to the req and res objects, and a next() function. This next() call is vital; it passes control to the next middleware in the stack or the final route handler. Middleware can perform various tasks: logging requests, parsing JSON bodies (express.json()), authenticating users, validating input, or adding properties to the req object for subsequent handlers. They provide a clean, modular way to process requests step-by-step.
Effective error handling is critical for any robust API. In Express, this is achieved using special middleware functions that take four arguments: (err, req, res, next). When an error occurs within a route handler or another middleware (e.g., by calling next(error)), Express skips subsequent regular middleware and routes, immediately invoking the error-handling middleware. It's crucial to place these error handlers after all your regular routes and middleware. This centralized approach allows you to catch errors, log them, and send consistent, user-friendly error responses (e.g., a JSON object with a status code and message) instead of exposing sensitive internal server details.
Key Takeaways
- Routing defines how your API responds to different HTTP methods and paths.
- Middleware functions execute sequentially, performing tasks like logging, authentication, or data parsing using
req,res, andnext(). - The
next()function is essential for passing control through the middleware chain. - Error handling middleware
(err, req, res, next)catches errors and provides consistent responses. - The order of middleware and routes matters significantly for correct execution and error handling.
Code Example
How this code works
This Express.js application sets up a basic web server to demonstrate how requests flow through middleware, are handled by routes, and how errors are managed. It begins by initializing express and creating an app instance. The first app.use defines a Request Logger middleware. This function runs for every incoming request, logs its method, URL, and timestamp to the console, and then crucially calls next() to pass control to the next part of the request processing pipeline. This global middleware ensures all requests are logged before any specific routing logic is applied.
Next, the app.get('/users/:id', ...) defines a specific route handler for GET requests to /users/ followed by an ID. It extracts the userId using req.params.id. If the ID is '123', it responds with user data using res.json(). Otherwise, it explicitly signals an error by calling next(new Error('User not found')). This directs control to the special Error handling middleware, which is also an app.use but with four arguments ((err, req, res, next)). This middleware must be placed last in the app.use chain; it catches any errors passed with next(err), logs the error stack with console.error, and sends a 500 status response with an error message using res.status().json(). Finally, app.listen starts the server.