DEV Community

Cover image for 5 Best Practices in Handling HTTP Errors in JavaScript
Jollen Moyani for Syncfusion, Inc.

Posted on • Originally published at syncfusion.com on

5 Best Practices in Handling HTTP Errors in JavaScript

Errors are an everyday obstacle that all developers and clients face. A typical error is when applications or a particular function breaks due to its inability to handle the logic or parameters.

JavaScript errors are similar to those found in other languages, as they follow the same principles. Following best practices for error handling ensures that the components will not break when the application runs into an error.

This article covers some best practices in handling HTTP errors within a JavaScript application.

Types of Errors: Operational and Programmer Errors

Most errors within applications are due to mistakes made by developers in their development processes. However, this is not the case for all errors.

These errors fall into two categories: operational and programmer.

Operational Errors

These are the type of errors seen during the application’s runtime. It does not mean there are bugs within the application, however. These errors come from within the JavaScript runtime environment.

Some of the most common operational errors include:

  • Server returning HTTP 500 response.
  • Request timing out.
  • Failing to resolve the hostname.

Programmer Errors

Programmer errors are issues within the application’s code, most likely introduced by the developers when building the application. Therefore, these errors are bugs within the application, and efficient remediation is a must to avoid issues.

Some of the most common programmer errors include:

  • Not catching a rejected promise.
  • Passing a string variable when the input expects an object.
  • Passing incorrect parameters into a function.

Best Practices for Handling HTTP Errors in JavaScript

Even though these are two different types of errors, they can both cause issues that affect the application’s performance.

All errors within the application must be dealt with appropriately. Adhering to best practices is a good start.

The following best practices cover the most common issues with error handling in JavaScript.

Specific Error Messages

Taking shortcuts may tempt developers into including generic error messages within the application so that multiple errors have the same output. Since the developer can reuse the same error message and code to handle most errors thrown by the application or a specific function, this method saves time.

However, having generic error messages within an application makes it less user-friendly, as understanding or troubleshooting them becomes tedious for users.

Best practice says that different errors must have individual and unique error messages displayed to the user. This approach allows users to understand and troubleshoot errors efficiently.

For example, developers may use libraries to initiate HTTP requests. The following code shows how developers can handle HTTP errors within Axios.

axios.get('/user/test').catch(function (error) {
 if (error.response) {
  // The request was made and the server responded with a status code that falls out of the range of 2xx
  console.log(error.response.data);
  console.log(error.response.status);
  console.log(error.response.headers);
  if (error.response.status === 500){
    //Custom Error Handler
    handlehttp500();
  }
  else if (error.response.status === 404){
    //Custom Error Handler
    handlehttp404();
  }
  else {
    handlehttpgenericerror();
  }
 }
});
Enter fullscreen mode Exit fullscreen mode

Use Custom Error Classes to Define Specific Errors

Handling errors using native classes would provide an easy way around handling errors within an application. However, this brings in added complexity and makes the code less readable.

The use of custom error classes is a workaround for this issue. Custom error classes bring in more readability and customization to define specific errors within the application.

The following code snippet shows an example of this scenario extended for handling an HTTP 404 error.

class ResourceNotFoundError extends Error {
  constructor(code, message) {
    super(message);
    this.code = code;
    this.name = "ResourceNotFoundError";
  }
}

const doSomething = () => {
  try {
    throw new ResourceNotFoundError(404, "Resource not found");
  } catch (err) {
    if (err instanceof ResourceNotFoundError) {
      // error instance of ResourceNotFoundError
      console.log(err.code);
      console.log(err.message);
      return;
    }
    console.log(err);
  }
};

doSomething();
Enter fullscreen mode Exit fullscreen mode

The replication of the same methods can let you reuse the same error class within the application, thus not requiring the developer to define the error classes repeatedly within the different classes.

Use Middleware

As an application grows in size and complexity, managing errors within the code becomes exhausting. An easy solution to this issue is using middleware to configure centralized error handling within the application.

Middleware provides added versatility in defining what happens when an error occurs. Developers can define the necessary actions for each error and where to send them by configuring notifications via alert notifications.

A centrally managed error handling mechanism reduces the risk of accidentally exposing errors to application users, since all errors have a single management point.

Use Promise-Based Error Handling Instead of Callbacks

Using callbacks for handling errors has been the go-to method for a long time. However, this method makes the code unreadable when the functions within the callbacks keep expanding.

In this example, the code requires multiple catch clauses to handle all the errors thrown from within the nested callback functions.

const fetchUsersCallback = () => {  
   // random url  
  const URL = '';  
  fetch(URL).then((success) => {  
    success.json().then((loggedinuser) => {  
      // do something with the data  
    }).catch((err) => {  
      console.log(err);  
    })  
  }).catch((error) => {  
    console.log(error);  
  });  
}

Enter fullscreen mode Exit fullscreen mode

However, using promise-based error handling, the same section of code looks cleaner and much more readable, reducing the number of lines required to achieve the same functionality.

const fetchUsersPromise = async () => {
    // random urlconst URL = '';
    try {   
      const resp = await fetch(URL);
      const parsedResp = await resp.json();
    } catch (err) {
        console.log(err)
    }
}
Enter fullscreen mode Exit fullscreen mode

It also does not require multiple instances to throw the error from this section and instead only defines a single catch clause to conduct this function.

Using a Centralized Location for Logs and Error Alerting

Handling errors is only a part of the solution when it comes to error management within complex applications. Even though the application implements proper error management, developers must manually dig through individual stack traces to identify the issues. This method is immensely time-consuming and ineffective in proactively identifying issues.

This is where a centralized location for logs comes in to allow all the errors and logs to reside within a single location for easy access and management. Developers may consider adding a centralized log management solution such as Elasticsearch to collect and aggregate all the errors that the application throws.

Dedicated solutions such as Elasticsearch allow developers to use advanced analytics to identify patterns, drill down into specific errors, and correlate them with other logs and metrics to provide improved insights into the collected errors.

Apart from collecting errors in a centralized location, developers may also use alerting functionality to make detecting specific errors easier within complicated applications.

Key Takeaways

In this article, I have discussed five of the best practices that allow developers to be on top of managing HTTP errors within JavaScript applications. These best practices lay the foundation for good error-handling.

I hope you have found this helpful. Thank you for reading!

The Syncfusion JavaScript suiteis the only suite you will ever need to build an application. It contains over 65 high-performance, lightweight, modular, and responsive UI components in a single package. Download the free trial and evaluate the controls today.

If you have any questions or comments, you can contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!

Related blogs

Top comments (0)