Handle HTTP Errors with Custom Messages in React Using

In Angular, we have tools like HttpClient, HttpErrorResponse, and HttpHeaders from @angular/common/http that make handling HTTP errors much easier. For example, when making a POST request using RxJS, we can easily handle different error types using ErrorEvent in the code below:

Here the code I wrote:

codeprivate runBuild(jobName: string, payload: string) {
return this.http.post(this.jenkinsURLs.runJobUrl(jobName), "json=" + encodeURIComponent(payload), httpOptions)
.pipe(catchError(this.handleError));
};

private handleError(error: HttpErrorResponse) {
let errorMessage: string = '';
if (error.error instanceof ErrorEvent) {
errorMessage = 'An error occurred: ' + error.error.message;
} else {
errorMessage = `Jenkins returned code ${error.status}, body was: ${error.message}`;
}
return throwError(errorMessage);
};

In this Angular code, we can distinguish between client-side and server-side errors using ErrorEvent. However, in React, we don’t have a built-in ErrorEvent equivalent. So, if I want to show different messages for different error codes, I have to handle it manually.

I’m looking for a generic way in React to replicate this kind of behavior. Ideally, I’d like some solution that allows me to use something like instanceof to detect different error types and assign custom messages accordingly. Does anyone have suggestions on how to implement this kind of error handling in a React app?

The provided code is an Angular TypeScript example that demonstrates how to make an HTTP POST request using HttpClient and handle different types of errors with custom messages. The code snippet uses RxJS operators to catch errors and distinguish between client-side and server-side issues.

Explanation:

  1. runBuild Function:
    • This function takes a jobName and payload as parameters, makes a POST request to a Jenkins job URL, and sends the payload as the request body.
    • The URL for the POST request is constructed using this.jenkinsURLs.runJobUrl(jobName).
    • httpOptions contains additional HTTP request options, such as headers.
    • The request uses RxJS’s pipe to attach an error handler via catchError.
  2. handleError Function:
    • This function is used to handle errors that occur during the HTTP request.
    • It checks if the error is a client-side or network-related error using instanceof ErrorEvent.
    • If it’s an ErrorEvent, it means something went wrong on the client-side (e.g., network error).
    • Otherwise, it means the server responded with an error, so the error message contains the HTTP status code and message.
    • The function returns an observable that emits the error message using throwError.

Corrected Code Example:

To implement this in an Angular project correctly, you can follow the code below. This example uses the latest RxJS practices and TypeScript.

codeimport { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, throwError } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class JenkinsService {
private jenkinsURLs = {
runJobUrl: (jobName: string) => `https://your-jenkins-server.com/job/${jobName}/build`,
};

private httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
}),
};

constructor(private http: HttpClient) {}

runBuild(jobName: string, payload: string) {
return this.http
.post(
this.jenkinsURLs.runJobUrl(jobName),
"json=" + encodeURIComponent(payload),
this.httpOptions
)
.pipe(
catchError(this.handleError) // Handling errors
);
}

private handleError(error: HttpErrorResponse) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// Client-side error
errorMessage = 'A client-side or network error occurred: ' + error.error.message;
} else {
// Server-side error
errorMessage = `Jenkins returned code ${error.status}, message was: ${error.message}`;
}
// Return an observable with a user-facing error message
return throwError(() => new Error(errorMessage));
}
}

Explanation of the Corrected Code:

  1. JenkinsService Class:
    • The service is injectable and can be provided in the root module of an Angular application.
    • The jenkinsURLs object stores the Jenkins job URL generation logic, making it easier to manage.
  2. HTTP Request (runBuild Method):
    • Makes a POST request to Jenkins with the provided jobName and payload.
    • The payload is encoded and sent as the body of the request.
    • Uses pipe with catchError to catch any errors during the HTTP request.
  3. Error Handling (handleError Method):
    • Distinguishes between client-side errors (e.g., network issues) and server-side errors (e.g., failed HTTP response).
    • Uses throwError to create an observable that emits the error message, ensuring proper error propagation.
  4. Modern Angular and RxJS Practices:
    • throwError is used with a callback function to create a new Error instance, following RxJS best practices.

Usage:

To use this service, inject it into a component and call the runBuild method:

code@Component({
selector: 'app-jenkins',
templateUrl: './jenkins.component.html',
})
export class JenkinsComponent {
constructor(private jenkinsService: JenkinsService) {}

triggerBuild() {
const jobName = 'my-job';
const payload = '{"param1": "value1", "param2": "value2"}';

this.jenkinsService.runBuild(jobName, payload).subscribe({
next: (response) => console.log('Build triggered successfully:', response),
error: (error) => console.error('Build failed:', error.message),
});
}
}

This example provides a complete solution for making HTTP requests and handling errors in an Angular environment.

Related blog posts