view data fixes
This commit is contained in:
154
apps/website/lib/gateways/api/base/ApiError.ts
Normal file
154
apps/website/lib/gateways/api/base/ApiError.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Enhanced API Error with detailed classification and context
|
||||
*/
|
||||
|
||||
export type ApiErrorType =
|
||||
| 'NETWORK_ERROR' // Connection failed, timeout, CORS
|
||||
| 'AUTH_ERROR' // 401, 403 - Authentication/Authorization issues
|
||||
| 'VALIDATION_ERROR' // 400 - Bad request, invalid data
|
||||
| 'NOT_FOUND' // 404 - Resource not found
|
||||
| 'SERVER_ERROR' // 500, 502, 503 - Server-side issues
|
||||
| 'RATE_LIMIT_ERROR' // 429 - Too many requests
|
||||
| 'CANCELED_ERROR' // Request was canceled
|
||||
| 'TIMEOUT_ERROR' // Request timeout
|
||||
| 'UNKNOWN_ERROR'; // Everything else
|
||||
|
||||
export interface ApiErrorContext {
|
||||
endpoint?: string;
|
||||
method?: string;
|
||||
requestBody?: unknown;
|
||||
timestamp: string;
|
||||
statusCode?: number;
|
||||
responseText?: string;
|
||||
retryCount?: number;
|
||||
wasRetry?: boolean;
|
||||
troubleshooting?: string;
|
||||
source?: string;
|
||||
componentStack?: string;
|
||||
isRetryable?: boolean;
|
||||
isConnectivity?: boolean;
|
||||
developerHint?: string;
|
||||
}
|
||||
|
||||
export class ApiError extends Error {
|
||||
public readonly type: ApiErrorType;
|
||||
public readonly context: ApiErrorContext;
|
||||
public readonly originalError?: Error;
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
type: ApiErrorType,
|
||||
context: ApiErrorContext,
|
||||
originalError?: Error
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
this.type = type;
|
||||
this.context = context;
|
||||
this.originalError = originalError;
|
||||
|
||||
// Maintains proper stack trace for where our error was thrown
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, ApiError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User-friendly message for production environments
|
||||
*/
|
||||
getUserMessage(): string {
|
||||
switch (this.type) {
|
||||
case 'NETWORK_ERROR':
|
||||
return 'Unable to connect to the server. Please check your internet connection.';
|
||||
case 'AUTH_ERROR':
|
||||
return 'Authentication required. Please log in again.';
|
||||
case 'VALIDATION_ERROR':
|
||||
return 'The data you provided is invalid. Please check your input.';
|
||||
case 'NOT_FOUND':
|
||||
return 'The requested resource was not found.';
|
||||
case 'SERVER_ERROR':
|
||||
return 'Server is experiencing issues. Please try again later.';
|
||||
case 'RATE_LIMIT_ERROR':
|
||||
return 'Too many requests. Please wait a moment and try again.';
|
||||
case 'TIMEOUT_ERROR':
|
||||
return 'Request timed out. Please try again.';
|
||||
case 'CANCELED_ERROR':
|
||||
return 'Request was canceled.';
|
||||
default:
|
||||
return 'An unexpected error occurred. Please try again.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Developer-friendly message with full context
|
||||
*/
|
||||
getDeveloperMessage(): string {
|
||||
const base = `[${this.type}] ${this.message}`;
|
||||
const ctx = [
|
||||
this.context.method,
|
||||
this.context.endpoint,
|
||||
this.context.statusCode ? `status:${this.context.statusCode}` : null,
|
||||
this.context.retryCount ? `retry:${this.context.retryCount}` : null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
return ctx ? `${base} ${ctx}` : base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this error is retryable
|
||||
*/
|
||||
isRetryable(): boolean {
|
||||
const retryableTypes: ApiErrorType[] = [
|
||||
'NETWORK_ERROR',
|
||||
'SERVER_ERROR',
|
||||
'RATE_LIMIT_ERROR',
|
||||
'TIMEOUT_ERROR',
|
||||
];
|
||||
return retryableTypes.includes(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this error indicates connectivity issues
|
||||
*/
|
||||
isConnectivityIssue(): boolean {
|
||||
return this.type === 'NETWORK_ERROR' || this.type === 'TIMEOUT_ERROR';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error severity for logging
|
||||
*/
|
||||
getSeverity(): 'error' | 'warn' | 'info' {
|
||||
switch (this.type) {
|
||||
case 'AUTH_ERROR':
|
||||
case 'VALIDATION_ERROR':
|
||||
case 'NOT_FOUND':
|
||||
return 'warn';
|
||||
case 'RATE_LIMIT_ERROR':
|
||||
case 'CANCELED_ERROR':
|
||||
return 'info';
|
||||
default:
|
||||
return 'error';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guards for error classification
|
||||
*/
|
||||
export function isApiError(error: unknown): error is ApiError {
|
||||
return error instanceof ApiError;
|
||||
}
|
||||
|
||||
export function isNetworkError(error: unknown): boolean {
|
||||
return isApiError(error) && error.type === 'NETWORK_ERROR';
|
||||
}
|
||||
|
||||
export function isAuthError(error: unknown): boolean {
|
||||
return isApiError(error) && error.type === 'AUTH_ERROR';
|
||||
}
|
||||
|
||||
export function isRetryableError(error: unknown): boolean {
|
||||
return isApiError(error) && error.isRetryable();
|
||||
}
|
||||
Reference in New Issue
Block a user