Utility functions that enhance the capabilities of your applications in Node JS.

The ‘util‘ module is an integral part of Node.js and offers a set of utility functions that enhance the capabilities of your applications. These functions cover a wide range of tasks, from working with objects and prototypes to managing asynchronous operations.

To begin using the ‘util’ module in Node.js, you need to require it as follows:

const util = require('util');

Once you’ve imported the ‘util‘ module, you can access its utility functions to simplify various programming tasks.

When to use the ‘util’ module

  1. Object Manipulation: The ‘util’ module provides functions for inspecting and manipulating objects, making it useful when working with complex data structures.
  2. Promises and Callbacks: If you need to work with callbacks or promises, the ‘util’ module offers functions for converting between them, streamlining asynchronous code.
  3. Inheritance and Prototypes: It simplifies the creation of classes and prototypes, making it easier to work with inheritance and object-oriented programming in JavaScript.
  4. Debugging and Inspecting: When debugging or inspecting objects, you can use the ‘util’ module to display objects in a more readable and structured format.
  5. Custom Error Classes: For building custom error classes, the ‘util’ module offers utility functions to simplify the process.

Now, let’s explore complete code examples to illustrate the practical usage of the ‘util’ module.

Promisify a callback function

const util = require('util');
const fs = require('fs');
const readFileAsync = util.promisify(fs.readFile);
readFileAsync('example.txt', 'utf8')
  .then((data) => {
    console.log('File content:', data);
  })
  .catch((err) => {
    console.error('Error reading file:', err);
  });

In this example, we use util.promisify to convert the callback-based fs.readFile function into a promise-based function, making it easier to work with promises and async/await.

Create a custom error class

const util = require('util');
class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
    this.code = 500;
  }
}
const customError = new CustomError('Something went wrong.');
console.error(util.inspect(customError, { depth: null }));

Here, we create a custom error class CustomError that extends the built-in Error class. We use util.inspect to display the error object in a readable format.

Advantages of using the ‘util’ module

  1. Simplified Asynchronous Code: The ‘util’ module’s promisify function makes it easier to work with asynchronous operations by converting callback-based functions into promise-based functions.
  2. Object Inspection: It provides a structured way to inspect and debug objects, helping developers understand complex data structures.
  3. Custom Error Classes: Building custom error classes becomes more straightforward, enabling better error handling and debugging.
  4. Inheritance: The ‘util’ module’s utility functions simplify object-oriented programming and prototype inheritance in JavaScript.

Disadvantages of using the ‘util’ module

  1. Dependency on Node.js: The ‘util’ module is specific to Node.js and may not be available in other JavaScript environments, limiting the portability of your code.
  2. Learning Curve: Some utility functions in the ‘util’ module may require a deeper understanding of JavaScript concepts, which could be challenging for novice developers.
  3. Overhead: In certain cases, using ‘util’ functions may introduce a slight performance overhead compared to manually implementing equivalent functionality.

Example: Building a REST API with custom error handling

Let’s explore a real-world use case for the ‘util’ module by building a RESTful API that handles custom errors gracefully. In this example, we create custom error classes using the ‘util’ module to improve error handling and make the API more informative.

const util = require('util');
class CustomError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.name = this.constructor.name;
    this.statusCode = statusCode || 500;
  }
}
class NotFoundError extends CustomError {
  constructor(message) {
    super(message || 'Not Found', 404);
  }
}
const express = require('express');
const app = express();
app.get('/user/:id', (req, res, next) => {
  const { id } = req.params;
  if (id !== '123') {
    return next(new NotFoundError(`User with ID ${id} not found`));
  }
  res.json({ id, name: 'John Doe' });
});
app.use((err, req, res, next) => {
  if (err instanceof CustomError) {
    res.status(err.statusCode).json({ error: err.message });
  } else {
    console.error(util.inspect(err, { depth: null }));
    res.status(500).json({ error: 'Internal Server Error' });
  }
});
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

In this example, we create custom error classes CustomError and NotFoundError using the ‘util’ module. These error classes provide more context and structured error responses in our REST API.

Author: user