Learn how to manage errors in HTTP calls using TypeScript, understand common HTTP error codes, and implement user-friendly error messages and retry logic.
In this section, we will explore how to effectively handle errors that occur during HTTP calls in TypeScript. As we interact with APIs and web services, understanding how to manage errors is crucial for building robust and user-friendly applications. We’ll cover common HTTP error codes, techniques for detecting and handling these errors, and best practices for providing feedback to users.
HTTP status codes are issued by a server in response to a client’s request made to the server. They are grouped into five classes, each representing a different category of response:
Let’s focus on the 4xx and 5xx series, as they are the most relevant for error handling:
When making HTTP requests in TypeScript, we can use the fetch
API or libraries like Axios. Both provide mechanisms to detect and handle errors. Let’s start with the fetch
API.
fetch
APIThe fetch
API returns a Promise
that resolves to the Response
object representing the response to the request. Here’s how you can handle errors using fetch
:
async function fetchData(url: string): Promise<void> {
try {
const response = await fetch(url);
// Check if the response status is not OK (200-299)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}
fetchData('https://api.example.com/data');
In this example, we check if the response.ok
property is false
, which indicates an error status code. We then throw an error with a message that includes the status code.
Axios is a popular HTTP client library that simplifies error handling. It automatically throws an error for responses with status codes outside the range of 2xx.
import axios from 'axios';
async function fetchData(url: string): Promise<void> {
try {
const response = await axios.get(url);
console.log(response.data);
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Axios error:', error.message);
console.error('Response status:', error.response?.status);
} else {
console.error('Unexpected error:', error);
}
}
}
fetchData('https://api.example.com/data');
Here, we use axios.isAxiosError
to check if the error is an Axios error. This allows us to access additional information, such as the response status.
When an error occurs, it’s important to provide users with clear and helpful messages. Avoid technical jargon and focus on what the user can do next.
function handleError(status: number): string {
switch (status) {
case 400:
return 'There was a problem with your request. Please check and try again.';
case 401:
return 'You are not authorized to view this content. Please log in.';
case 404:
return 'The requested resource could not be found.';
case 500:
return 'There is a problem with the server. Please try again later.';
default:
return 'An unexpected error occurred. Please try again.';
}
}
// Usage
const errorMessage = handleError(404);
console.log(errorMessage);
Sometimes, errors are temporary and can be resolved by retrying the request. Implementing retry logic can improve the resilience of your application.
async function fetchDataWithRetry(url: string, retries: number = 3): Promise<void> {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
return; // Exit the function if successful
} catch (error) {
console.error(`Attempt ${attempt} failed:`, error);
if (attempt === retries) {
console.error('All retry attempts failed.');
}
}
}
}
fetchDataWithRetry('https://api.example.com/data');
In this example, we attempt to fetch data up to three times before giving up. Each failed attempt logs an error message.
Logging errors is crucial for debugging and monitoring the health of your application. It helps you identify patterns and recurring issues.
function logError(error: Error, context: string): void {
console.error(`Error in ${context}:`, error.message);
// Additional logging logic, such as sending logs to a server
}
// Usage
try {
// Some operation that may throw an error
} catch (error) {
logError(error, 'fetchData');
}
When handling errors, it’s important to avoid exposing sensitive information. Here are some best practices:
To better understand the flow of error handling in HTTP calls, let’s visualize it using a flowchart.
graph TD; A[Start] --> B[Make HTTP Request]; B --> C{Response Status}; C -->|Success| D[Process Data]; C -->|Error| E[Log Error]; E --> F[Display User-Friendly Message]; F --> G{Retry?}; G -->|Yes| B; G -->|No| H[End]; D --> H;
Diagram Description: This flowchart illustrates the process of making an HTTP request, checking the response status, logging errors, displaying user-friendly messages, and retrying the request if necessary.
Now that we’ve covered the basics of error handling in HTTP calls, try modifying the code examples to:
In this section, we explored how to handle errors in HTTP calls using TypeScript. We learned about common HTTP error codes, how to detect and handle these errors, and best practices for providing user-friendly messages and secure error handling. By implementing these techniques, you can create more resilient and user-friendly applications.