mindmap / frontend /src /utils /apiUtils.ts
Rsnarsna's picture
Upload 44 files
b0c3c39 verified
import axios, { AxiosError } from 'axios';
export interface ApiError {
message: string;
details?: string;
code?: string;
}
interface ApiErrorResponse {
message?: string;
error?: string;
details?: string;
}
export const handleApiError = (error: unknown): ApiError => {
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError<ApiErrorResponse>;
const responseData = axiosError.response?.data;
return {
message: axiosError.message,
details: responseData?.message || responseData?.error || 'Unknown error occurred',
code: axiosError.code,
};
}
if (error instanceof Error) {
return {
message: error.message,
details: error.stack,
};
}
return {
message: 'An unexpected error occurred',
details: String(error),
};
};
export const withRetry = async <T>(
operation: () => Promise<T>,
maxRetries: number = 3,
delay: number = 1000
): Promise<T> => {
let lastError: unknown;
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
lastError = error;
if (i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i)));
}
}
}
throw lastError;
};
export const validateInput = (input: string, maxLength: number = 100): boolean => {
if (!input || typeof input !== 'string') return false;
if (input.trim().length === 0) return false;
if (input.length > maxLength) return false;
return true;
};
export const sanitizeInput = (input: string): string => {
return input
.trim()
.replace(/[<>]/g, '') // Remove potential HTML tags
.replace(/javascript:/gi, '') // Remove potential JavaScript protocol
.slice(0, 100); // Limit length
};
// Rate limiting utility
export class RateLimiter {
private timestamps: number[] = [];
private readonly windowMs: number;
private readonly maxRequests: number;
constructor(windowMs: number = 60000, maxRequests: number = 100) {
this.windowMs = windowMs;
this.maxRequests = maxRequests;
}
canMakeRequest(): boolean {
const now = Date.now();
this.timestamps = this.timestamps.filter(time => now - time < this.windowMs);
if (this.timestamps.length >= this.maxRequests) {
return false;
}
this.timestamps.push(now);
return true;
}
}
// Create a rate limiter instance
export const rateLimiter = new RateLimiter();
// Wrapper for API calls with rate limiting
export const rateLimitedApiCall = async <T>(
apiCall: () => Promise<T>,
retryCount: number = 3
): Promise<T> => {
if (!rateLimiter.canMakeRequest()) {
throw new Error('Rate limit exceeded. Please try again later.');
}
return withRetry(apiCall, retryCount);
};