Open In App

TypeScript Custom Errors in RESTful API

Last Updated : 09 Aug, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will explore the importance of using custom error handling in TypeScript for RESTful APIs. We will begin by highlighting the problem statement, followed by demonstrating the problem with code examples and error outputs. Finally, we will present a solution approach using custom error classes and showcase the desired output. By the end, you will have a clear understanding of how to implement custom errors to improve error handling in your TypeScript-based RESTful APIs.

1. Problem Statement

When developing RESTful APIs in TypeScript, error handling plays a crucial role in providing meaningful feedback to clients and aiding in debugging. However, relying solely on default error classes like Error or HttpError often leads to generic error messages that may not convey specific information about the encountered issue. This can hinder effective troubleshooting and make it challenging to identify the root cause of errors.

Display the Error

Let’s examine a scenario where a user attempts to access a resource that requires authentication. We’ll demonstrate the problem by using default error classes and observing the resulting error message.

Javascript




import { Request, Response } from 'express';
  
// Example route handler
function getProtectedResource(req: Request, res: Response) {
    if (!req.user) {
        throw new Error('Authentication required!');
    }
  
    // Retrieve and send the protected resource
    res.json({ resource: 'Some sensitive data' });
}


When an unauthenticated user makes a request to this route, the server throws a generic Error with the message “Authentication required!”.

Output (Error):

abc.gif

Output

Solution Approach

To address the problem, we can implement custom error classes in TypeScript. These classes allow us to define specific error types that extend the base Error class, providing additional information and enhancing error handling.

Let’s create a custom error class called AuthenticationError for our scenario:

Javascript




class AuthenticationError extends Error {
    constructor() {
        super('Authentication required!');
        this.name = 'AuthenticationError';
    }
}


Now, we can modify our route handler to throw an instance of AuthenticationError instead of a generic Error:

Javascript




function getProtectedResource(req: Request, res: Response) {
    if (!req.user) {
        throw new AuthenticationError();
    }
  
    // Retrieve and send the protected resource
    res.json({ resource: 'Some sensitive data' });
}


By using a custom error class, we provide more specific information about the encountered issue, making it easier to understand and handle the error.

Output (Desired):

cde.gif

Output

In the desired output, the error message now includes the name of the custom error class (AuthenticationError), making it clear what type of error occurred. This improved clarity aids in debugging and enables developers to address issues more effectively.

2. Problem Statement

In this scenario, we have an API endpoint that fetches user data based on their ID. However, there may be cases where the requested user ID does not exist in the database. We want to handle this situation with a custom error class to provide a clear and meaningful error message.

Display the Error

Let’s consider the following code snippet:

Javascript




import { Request, Response } from 'express';
  
function getUserById(req: Request, res: Response) {
    const userId = req.params.id;
    const user = findUserById(userId);
  
    if (!user) {
        throw new Error('User not found!');
    }
  
    res.json(user);
}
  
function findUserById(userId: string) {
  
    // Logic to find the user by ID in the 
    // database ...
  
    // Assume the user was not found
    return null;
}


In this code, we have an API endpoint getUserById that takes a request object (req) and a response object (res). It retrieves the user ID from the request parameters, calls a findUserById function to fetch the user data from the database, and throws a generic Error with the message “User not found!” if the user does not exist.

Output (Error):

error1.gif

Output

The error message in this case is generic and does not provide specific information about the encountered issue, which makes it challenging to determine whether the user ID was invalid or if there was an issue with the database.

Solution Approach

To improve error handling, we can create a custom error class called UserNotFoundError that extends the Error class. This custom error class will convey the specific information that the requested user was not found.

Let’s define the UserNotFoundError class:

Javascript




class UserNotFoundError extends Error {
    constructor(userId: string) {
        super(`User not found with ID: ${userId}`);
        this.name = 'UserNotFoundError';
    }
}


In this code snippet, we define the UserNotFoundError class that extends the Error class. The constructor of the UserNotFoundError class takes the userId as a parameter and calls the parent Error class constructor with a specific error message that includes the ID of the user. We also set the name property of the error instance to “UserNotFoundError”.

Next, we modify our code to throw an instance of UserNotFoundError instead of a generic Error:

Javascript




function getUserById(req: Request, res: Response) {
    const userId = req.params.id;
    const user = findUserById(userId);
  
    if (!user) {
        throw new UserNotFoundError(userId);
    }
  
    res.json(user);
}


Now, when a user with an invalid ID is requested, the server throws an instance of UserNotFoundError, providing a clear and informative error message.

Output (Desired):

error2.gif

Output

In the desired output, the error message indicates the specific error type (UserNotFoundError) and includes the ID of the user that was not found. This information helps in identifying the exact error in the code.

Conclusion

In this article, we explored the significance of using custom error handling in TypeScript for RESTful APIs. By implementing custom error classes, we can provide more specific and informative error messages.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads