Node JS error handling Node.js and Express


Error handling in Node.js and Express is crucial for building reliable and robust applications. It involves managing both synchronous and asynchronous errors, ensuring that errors are reported effectively, and preventing the application from crashing due to unhandled issues. Here’s a detailed guide on error handling in Node.js and Express:

1. Error Handling in Node.js

1.1 Synchronous Error Handling

In synchronous code, use try and catch blocks to handle errors:

Example:

try { // Code that might throw an error const result = someFunction(); console.log(result); } catch (error) { // Handle the error console.error('An error occurred:', error.message); }

1.2 Asynchronous Error Handling

1.2.1 Callbacks

For asynchronous code using callbacks, handle errors with the error-first callback pattern:

Example:

const fs = require('fs'); fs.readFile('file.txt', 'utf8', (error, data) => { if (error) { // Handle the error console.error('An error occurred:', error.message); return; } // Process the data console.log(data); });

1.2.2 Promises

Handle errors in promises using .catch():

Example:

const fs = require('fs').promises; fs.readFile('file.txt', 'utf8') .then(data => { console.log(data); }) .catch(error => { console.error('An error occurred:', error.message); });

1.2.3 Async/Await

Use try/catch within async functions:

Example:

const fs = require('fs').promises; async function readFile() { try { const data = await fs.readFile('file.txt', 'utf8'); console.log(data); } catch (error) { console.error('An error occurred:', error.message); } } readFile();

1.3 Global Error Handling

For uncaught exceptions and unhandled promise rejections:

Example:

// Handle uncaught exceptions process.on('uncaughtException', (error) => { console.error('Uncaught Exception:', error.message); process.exit(1); // Optional: Exit the process }); // Handle unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'reason:', reason); process.exit(1); // Optional: Exit the process });

2. Error Handling in Express.js

Express.js provides a structured approach to handle errors through middleware.

2.1 Basic Error-Handling Middleware

Define an error-handling middleware function with four arguments: err, req, res, and next.

Example:

const express = require('express'); const app = express(); const port = 3000; // Define a route that may throw an error app.get('/', (req, res) => { throw new Error('Something went wrong!'); }); // Basic error-handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!'); }); app.listen(port, () => { console.log(`Server is running at http://localhost:${port}`); });

2.2 Handling Specific Errors

Customize error handling based on error types or properties:

Example:

app.use((err, req, res, next) => { if (err instanceof SyntaxError) { res.status(400).send('Bad JSON format'); } else if (err.status === 404) { res.status(404).send('Not Found'); } else { console.error(err.stack); res.status(500).send('Internal Server Error'); } });

2.3 Asynchronous Error Handling in Routes

Handle errors in asynchronous route handlers by passing them to the next middleware:

Example:

app.get('/async', async (req, res, next) => { try { const data = await someAsyncFunction(); res.send(data); } catch (error) { next(error); // Pass the error to the error-handling middleware } });

2.4 Using Third-Party Middleware for Error Handling

You can use third-party middleware to simplify error handling. For example, express-async-errors helps with handling asynchronous errors:

Installation:

npm install express-async-errors

Usage:

const express = require('express'); require('express-async-errors'); // Import this module before defining routes const app = express(); const port = 3000; app.get('/async', async (req, res) => { const data = await someAsyncFunction(); res.send(data); }); // Error-handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something went wrong!'); }); app.listen(port, () => { console.log(`Server is running at http://localhost:${port}`); });

3. Best Practices for Error Handling

  1. Graceful Degradation: Ensure your application can handle errors and continue operating where possible.
  2. Error Logging: Use logging mechanisms to capture error details for debugging and monitoring.
  3. User-Friendly Messages: Provide clear and informative error messages to end-users.
  4. Consistent Error Responses: Use a consistent format for error responses in APIs.
  5. Avoid Exposing Sensitive Information: Don’t expose stack traces or internal details in error responses.
  6. Test Error Scenarios: Test your error handling thoroughly to ensure robustness.