In any web application, encountering errors is inevitable. Proper error handling is crucial to ensure a smooth user experience and maintain the stability of your application. In this section, we will explore best practices for handling errors in Express.js applications.
Error handling in Express.js can be done using middleware functions. Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. These functions can execute any code, make changes to the request and the response objects, end the request-response cycle, and call the next middleware function.
Express.js provides several ways to handle errors:
err, req, res, and next. It must be defined after all other app.use() and routes calls.Error-handling middleware functions have four arguments: (err, req, res, next). The first argument is the error object. If you need to pass any data to the error handler, you can do so by attaching it to the req or res objects.
Here's an example of how to define and use error-handling middleware:
1app.use((err, req, res, next) => {2console.error(err.stack);3res.status(500).send('Something broke!');4});
Express has a built-in error handler that is added at the end of all middleware functions. It sends an appropriate HTTP response based on the type of error.
If you have defined any custom error-handling middleware, it will override the built-in error handler.
You can create custom error classes to handle specific types of errors. This makes your code more organized and easier to maintain.
Here's an example of how to define a custom error class:
1class ApiError extends Error {2constructor(message, statusCode) {3super(message);4this.statusCode = statusCode;5}6}78app.use((err, req, res, next) => {9if (err instanceof ApiError) {10return res.status(err.statusCode).json({ message: err.message });11}12res.status(500).send('Something broke!');13});
Let's look at some practical examples of error handling in Express.js.
In this example, we will create a route that throws an error if the user is not authorized to access it.
1app.get('/protected', (req, res) => {2throw new ApiError('Unauthorized access', 403);3});45app.use((err, req, res, next) => {6if (err instanceof ApiError) {7return res.status(err.statusCode).json({ message: err.message });8}9res.status(500).send('Something broke!');10});
In Express.js, errors that occur in asynchronous functions are not automatically passed to the error-handling middleware. You need to handle them manually.
Here's an example of how to handle async errors:
1app.get('/async', async (req, res) => {2try {3const result = await someAsyncFunction();4res.send(result);5} catch (err) {6next(err);7}8});910app.use((err, req, res, next) => {11if (err instanceof ApiError) {12return res.status(err.statusCode).json({ message: err.message });13}14res.status(500).send('Something broke!');15});
In the next section, we will explore how to use templates with Express.js. Templates allow you to generate HTML dynamically and make your application more dynamic.
Stay tuned for more tutorials on Express.js!