Comprehensive error handling with REST-specific error types, context information, and type guards for robust error management in HTTP operations.
Primary error type for HTTP request failures with rich context and standard error codes.
/**
* A custom error type for failed pipeline requests
*/
interface RestError extends Error {
/**
* The error code, if available
*/
code?: string;
/**
* The HTTP status code of the request, if applicable
*/
statusCode?: number;
/**
* The request that was made
*/
request?: PipelineRequest;
/**
* The response received, if any
*/
response?: PipelineResponse;
}
/**
* RestError constructor interface with error codes
*/
interface RestErrorConstructor {
/**
* Something went wrong when making the request.
* This means the actual request failed for some reason,
* such as a DNS issue or the connection being lost.
*/
readonly REQUEST_SEND_ERROR: string;
/**
* This means that parsing the response from the server failed.
* It may have been malformed.
*/
readonly PARSE_ERROR: string;
/**
* Creates a new RestError instance
* @param message - The error message
* @param options - Additional options for the error
*/
new (message: string, options?: RestErrorOptions): RestError;
}
/**
* The RestError constructor
*/
const RestError: RestErrorConstructor;
interface RestErrorOptions {
/**
* The code of the error itself (use statics on RestError if possible)
*/
code?: string;
/**
* The HTTP status code of the request (if applicable)
*/
statusCode?: number;
/**
* The request that was made
*/
request?: PipelineRequest;
/**
* The response received (if any)
*/
response?: PipelineResponse;
}Usage Examples:
import { RestError, type RestErrorOptions } from "@azure/core-rest-pipeline";
// Handle RestError in request processing
try {
const response = await pipeline.sendRequest(client, request);
console.log(response.bodyAsText);
} catch (error) {
if (error instanceof RestError) {
console.error(`Request failed with status ${error.statusCode}`);
console.error(`Error code: ${error.code}`);
console.error(`Request URL: ${error.request?.url}`);
console.error(`Response headers:`, error.response?.headers.toJSON());
}
}
// Create custom RestError
const customError = new RestError("Custom request failed", {
code: "CUSTOM_ERROR",
statusCode: 400,
request: myRequest,
response: myResponse
});
// Use standard error codes
const networkError = new RestError("Network connection failed", {
code: RestError.REQUEST_SEND_ERROR
});
const parseError = new RestError("Response parsing failed", {
code: RestError.PARSE_ERROR
});Type guard function to check if an error is a RestError instance.
/**
* Type guard to check if an error is a RestError
* @param error - The error to check
* @returns True if the error is a RestError, false otherwise
*/
function isRestError(error: unknown): error is RestError;Usage Examples:
import { isRestError } from "@azure/core-rest-pipeline";
// Generic error handling with type safety
async function makeRequest() {
try {
const response = await pipeline.sendRequest(client, request);
return response;
} catch (error) {
if (isRestError(error)) {
// TypeScript knows this is a RestError
console.error(`HTTP Error ${error.statusCode}: ${error.message}`);
if (error.statusCode === 429) {
const retryAfter = error.response?.headers.get("Retry-After");
console.log(`Rate limited. Retry after: ${retryAfter}`);
}
return null;
} else {
// Handle other error types
console.error("Non-HTTP error:", error);
throw error;
}
}
}
// Error filtering and logging
function logError(error: unknown) {
if (isRestError(error)) {
console.log({
type: "RestError",
message: error.message,
statusCode: error.statusCode,
code: error.code,
url: error.request?.url,
method: error.request?.method
});
} else if (error instanceof Error) {
console.log({
type: "Error",
message: error.message,
stack: error.stack
});
} else {
console.log({
type: "Unknown",
error: String(error)
});
}
}Standard error codes provided by RestError for common failure scenarios.
/**
* Standard error codes for common failure scenarios
*/
interface RestErrorConstructor {
/**
* Something went wrong when making the request.
* This means the actual request failed for some reason,
* such as a DNS issue or the connection being lost.
*/
readonly REQUEST_SEND_ERROR: string;
/**
* This means that parsing the response from the server failed.
* It may have been malformed.
*/
readonly PARSE_ERROR: string;
}Usage Examples:
import { RestError, isRestError } from "@azure/core-rest-pipeline";
// Handle specific error types
async function robustRequest() {
try {
return await pipeline.sendRequest(client, request);
} catch (error) {
if (isRestError(error)) {
switch (error.code) {
case RestError.REQUEST_SEND_ERROR:
console.error("Network or connectivity issue:", error.message);
// Maybe retry with exponential backoff
break;
case RestError.PARSE_ERROR:
console.error("Response parsing failed:", error.message);
// Log the raw response for debugging
console.error("Raw response:", error.response?.bodyAsText);
break;
default:
console.error("HTTP error:", error.statusCode, error.message);
break;
}
}
throw error;
}
}import { isRestError } from "@azure/core-rest-pipeline";
async function handleHttpErrors() {
try {
const response = await pipeline.sendRequest(client, request);
return response;
} catch (error) {
if (isRestError(error)) {
switch (error.statusCode) {
case 400:
throw new Error("Bad Request: Check your request parameters");
case 401:
throw new Error("Unauthorized: Check your authentication credentials");
case 403:
throw new Error("Forbidden: You don't have permission for this resource");
case 404:
throw new Error("Not Found: The requested resource doesn't exist");
case 429:
const retryAfter = error.response?.headers.get("Retry-After");
throw new Error(`Rate Limited: Retry after ${retryAfter} seconds`);
case 500:
throw new Error("Server Error: The service is experiencing issues");
default:
throw new Error(`HTTP ${error.statusCode}: ${error.message}`);
}
}
throw error;
}
}import { isRestError, RestError } from "@azure/core-rest-pipeline";
function shouldRetry(error: unknown, attempt: number, maxRetries: number): boolean {
if (attempt >= maxRetries) return false;
if (isRestError(error)) {
// Retry network errors
if (error.code === RestError.REQUEST_SEND_ERROR) {
return true;
}
// Retry specific HTTP status codes
if (error.statusCode && [429, 502, 503, 504].includes(error.statusCode)) {
return true;
}
// Don't retry client errors (4xx except 429)
if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
return false;
}
}
return false;
}
async function requestWithRetry(maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
try {
return await pipeline.sendRequest(client, request);
} catch (error) {
if (!shouldRetry(error, attempt, maxRetries)) {
throw error;
}
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}import { isRestError } from "@azure/core-rest-pipeline";
interface ErrorContext {
message: string;
statusCode?: number;
errorCode?: string;
requestId?: string;
url?: string;
method?: string;
timestamp: Date;
}
function extractErrorContext(error: unknown): ErrorContext {
const context: ErrorContext = {
message: error instanceof Error ? error.message : String(error),
timestamp: new Date()
};
if (isRestError(error)) {
context.statusCode = error.statusCode;
context.errorCode = error.code;
context.url = error.request?.url;
context.method = error.request?.method;
context.requestId = error.request?.requestId;
}
return context;
}
// Usage in error handling
try {
await pipeline.sendRequest(client, request);
} catch (error) {
const errorContext = extractErrorContext(error);
console.error("Request failed:", errorContext);
// Send to monitoring service
// monitoring.recordError(errorContext);
}