عميل HTTP متقدم بلغة TypeScript: من الطلبات الأساسية إلى الحلول الصناعية
عند تطوير تطبيقات الويب الحديثة بلغة TypeScript، يتجاوز العمل مع طلبات HTTP بكثير مجرد استدعاء fetch البسيط. على المستوى المتقدم، لا يلزم فقط إرسال الطلبات، بل أيضًا معالجة الأخطاء بكفاءة، وإدارة وقت الانتظار، وكتابة أنواع الاستجابات، وتطبيق المعترضات، وحتى تخزين البيانات مؤقتًا. في هذه المقالة، سنشرح كيفية بناء عميل HTTP موثوق ومرن بلغة TypeScript يناسب المشاريع الإنتاجية.
1. إنشاء عميل HTTP مكتوب الأنواع باستخدام الأدوية (Generics)
واحدة من المزايا الرئيسية لـ TypeScript هي الكتابة الصارمة للأنواع. سننشئ فئة أساسية HttpClient ستقبل نوع الاستجابة من خلال الأدوية. هذا سيساعد في تجنب الأخطاء في مرحلة الترجمة.
// types.tsexport interface ApiResponse<T> { data: T; status: number; ok: boolean;}
export interface RequestConfig { headers?: Record<string, string>; params?: Record<string, string>; signal?: AbortSignal;}
// http-client.tsimport { ApiResponse, RequestConfig } from './types';
class HttpClient { private baseUrl: string;
constructor(baseUrl: string) { this.baseUrl = baseUrl; }
async get<T>(endpoint: string, config?: RequestConfig): Promise<ApiResponse<T>> { const url = new URL(`${this.baseUrl}${endpoint}`); if (config?.params) { Object.entries(config.params).forEach(([key, value]) => { url.searchParams.append(key, value); }); }
const response = await fetch(url.toString(), { method: 'GET', headers: { 'Content-Type': 'application/json', ...config?.headers, }, signal: config?.signal, });
const data: T = await response.json(); return { data, status: response.status, ok: response.ok, }; }
async post<T, U>(endpoint: string, body: U, config?: RequestConfig): Promise<ApiResponse<T>> { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...config?.headers, }, body: JSON.stringify(body), signal: config?.signal, });
const data: T = await response.json(); return { data, status: response.status, ok: response.ok }; }}
export default HttpClient;2. معالجة الأخطاء والمهلات
يجب على العميل المتقدم معالجة كل من الأخطاء الشبكية وأخطاء منطق الأعمال بشكل صحيح. سنضيف آلية مهلة باستخدام AbortController ومعالجة مخصصة للأخطاء.
// errors.tsexport class HttpError extends Error { status: number; data?: unknown;
constructor(message: string, status: number, data?: unknown) { super(message); this.name = 'HttpError'; this.status = status; this.data = data; }}
export class TimeoutError extends Error { constructor(timeout: number) { super(`Request timed out after ${timeout}ms`); this.name = 'TimeoutError'; }}
// http-client.ts (إضافة)async requestWithTimeout<T>( endpoint: string, options: RequestInit, timeout: number = 5000): Promise<ApiResponse<T>> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout);
try { const response = await fetch(`${this.baseUrl}${endpoint}`, { ...options, signal: controller.signal, });
if (!response.ok) { const errorData = await response.json().catch(() => null); throw new HttpError( `HTTP ${response.status}: ${response.statusText}`, response.status, errorData ); }
const data: T = await response.json(); r