TypeScript HTTP क्लाइंट: A से Z तक सही तरीके से रिक्वेस्ट करें
\n\nआधुनिक वेब डेवलपमेंट में रिमोट सर्वर के साथ इंटरैक्शन बहुत ज़रूरी है। चाहे REST API से डेटा लेना हो, फॉर्म सबमिट करना हो या फ़ाइल अपलोड करनी हो — HTTP रिक्वेस्ट क्लाइंट-सर्वर आर्किटेक्चर की नींव हैं। TypeScript अपनी सख्त टाइपिंग और शक्तिशाली टूल्स के साथ HTTP रिक्वेस्ट को न सिर्फ सुरक्षित बनाता है, बल्कि मेंटेन करने में भी आसान बनाता है। इस आर्टिकल में हम सीखेंगे कि TypeScript में एक अच्छा HTTP क्लाइंट कैसे बनाएं, आम गलतियों से कैसे बचें और ऐसा कोड लिखें जो हमेशा सही काम करे।
\n\n1. बुनियादी बातें: fetch API और उसकी टाइपिंग
\n\nब्राउज़र में बिल्ट-इन fetch HTTP रिक्वेस्ट करने का एक आधुनिक और लचीला टूल है। लेकिन TypeScript में इसका उपयोग करते समय रिस्पॉन्स की सही टाइपिंग ज़रूरी है। डिफ़ॉल्ट रूप से fetch Promise<Response> लौटाता है, और हमें स्पष्ट रूप से बताना होता है कि हमें किस तरह का डेटा चाहिए।
interface User {\n id: number;\n name: string;\n email: string;\n}\n\nasync function getUser(id: number): Promise<User> {\n const response = await fetch(`https://api.example.com/users/${id}`);\n \n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n \n const data: User = await response.json();\n return data;\n}\n\n\nresponse.ok की जाँच करना बहुत ज़रूरी है। अगर सर्वर कोई एरर (404, 500 आदि) लौटाता है, तो fetch अपने आप एक्सेप्शन नहीं फेंकेगा। हमें स्टेटस को मैन्युअली हैंडल करना होगा।
POST रिक्वेस्ट के लिए बॉडी के साथ Content-Type हेडर देना ज़रूरी है:
async function createUser(userData: Omit<User, 'id'>): Promise<User> {\n const response = await fetch('https://api.example.com/users', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(userData),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create user: ${response.statusText}`);\n }\n\n return response.json();\n}\n\n\n2. एक यूनिवर्सल HTTP क्लाइंट बनाना
\n\nहर बार fetch को नए सिरे से लिखने के बजाय, एक रैपर — यूनिवर्सल HTTP क्लाइंट — बनाना बेहतर है। इससे बेस URL, हेडर और एरर हैंडलिंग को एक जगह मैनेज किया जा सकता है। आइए क्लास-बेस्ड उदाहरण देखें:
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\ninterface RequestConfig<TBody = unknown> {\n method: HttpMethod;\n url: string;\n body?: TBody;\n headers?: Record<string, string>;\n params?: Record<string, string>;\n}\n\nclass HttpClient {\n private baseUrl: string;\n private defaultHeaders: Record<string, string>;\n\n constructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n this.baseUrl = baseUrl;\n this.defaultHeaders = {\n 'Content-Type': 'application/json',\n ...defaultHeaders,\n };\n }\n\n private async request<TResponse, TBody = unknown>(\n config: RequestConfig<TBody>\n ): Promise<TResponse> {\n const url = new URL(`${this.baseUrl}${config.url}`);\n \n if (config.params) {\n Object.entries(config.params).forEach(([key, value]) => {\n url.searchParams.append(key, value);\n });\n }\n\n const response = await fetch(url.toString(), {\n method: config.method,\n headers: { ...this.defaultHeaders, ...config.headers },\n body: config.body ? JSON.stringify(config.body) : undefined,\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n throw new Error(`Request failed: ${response.status} ${response.statusText}. Body: ${errorBody}`);\n }\n\n // DELETE या अन्य मेथड्स के लिए जो बॉडी नहीं लौटाते\n if (response.status === 204) {\n return undefined as TResponse;\n }\n\n return response.json();\n }\n\n // सुविधाजनक मेथड्स\n async get<TResponse>(url: string, params?: Record<string, string>): Promise<TResponse> {\n return this.request<TResponse>({ method: 'GET', url, params });\n }\n\n async post<TResponse, TBody>(url: string, body: TBody): Promise<TResponse> {\n return this.request<TResponse, TBody>({ method: 'POST', url, body });\n }\n\n async put<TResponse, TBody>(url: string, body: TBody): Promise<TResponse> {\n return this.request<TResponse, TBody>({ method: 'PUT', url, body });\n }\n\n async delete<TResponse>(url: string): Promise<TResponse> {\n return this.request<TResponse>({ method: 'DELETE', url });\n }\n}\n\n\nइस क्लास का उपयोग करना बहुत आसान है:
\n\nconst api = new HttpClient('https://api.example.com');\n\n// GET रिक्वेस्ट\nconst users = await api.get<User[]>('/users', { page: '1', limit: '10' });\n\n// POST रिक्वेस्ट\nconst newUser = await api.post<User, Omit<User, 'id'>>('/users', {\n name: 'Rahul',\n email: 'rahul@example.com'\n});\n\n\n3. एरर हैंडलिंग और टाइप सेफ्टी
\n\nएक अच्छे HTTP क्लाइंट में एरर हैंडलिंग बहुत ज़रूरी है। हम एक कस्टम एरर क्लास बना सकते हैं:
\n\nclass HttpError extends Error {\n constructor(\n public statusCode: number,\n public statusText: string,\n public body: string\n ) {\n super(`HTTP ${statusCode}: ${statusText}`);\n this.name = 'HttpError';\n }\n}\n\n// HttpClient में request मेथड को अपडेट करें\nif (!response.ok) {\n const errorBody = await response.text();\n throw new HttpError(response.status, response.statusText, errorBody);\n}\n\n\nइससे एरर को टाइप-सेफ तरीके से हैंडल किया जा सकता है और यूज़र को स्पष्ट जानकारी दी जा सकती है।
\n\n4. इंटरसेप्टर और मिडलवेयर
\n\nबड़े एप्लिकेशन में, रिक्वेस्ट और रिस्पॉन्स को इंटरसेप्ट करना उपयोगी होता है — जैसे ऑथ टोकन जोड़ना या लॉगिंग करना। हम अपने क्लाइंट में इंटरसेप्टर जोड़ सकते हैं:
\n\ntype RequestInterceptor = (config: RequestConfig) => RequestConfig | Promise<RequestConfig>;\ntype ResponseInterceptor = (response: Response) => Response | Promise<Response>;\n\nclass HttpClient {\n private requestInterceptors: RequestInterceptor[] = [];\n private responseInterceptors: ResponseInterceptor[] = [];\n\n addRequestInterceptor(interceptor: RequestInterceptor) {\n this.requestInterceptors.push(interceptor);\n }\n\n addResponseInterceptor(interceptor: ResponseInterceptor) {\n this.responseInterceptors.push(interceptor);\n }\n\n private async request<TResponse, TBody = unknown>(...): Promise<TResponse> {\n let finalConfig = config;\n for (const interceptor of this.requestInterceptors) {\n finalConfig = await interceptor(finalConfig);\n }\n\n let response = await fetch(...);\n \n for (const interceptor of this.responseInterceptors) {\n response = await interceptor(response);\n }\n \n // बाकी कोड...\n }\n}\n\n\nइस तरह आप आसानी से ऑथेंटिकेशन, लॉगिंग या कैशिंग जोड़ सकते हैं।
\n\nनिष्कर्ष
\n\nTypeScript में एक अच्छा HTTP क्लाइंट बनाने से आपका कोड ज़्यादा सुरक्षित, मेंटेन करने योग्य और पुन: उपयोग करने योग्य बनता है। fetch API का सही उपयोग, टाइप सेफ्टी, एरर हैंडलिंग और इंटरसेप्टर — ये सभी चीज़ें एक प्रोफेशनल HTTP क्लाइंट की पहचान हैं।
\n\nअब आप अपने प्रोजेक्ट में इन तकनीकों का उपयोग करके बेहतर API इंटीग्रेशन कर सकते हैं। हैप्पी कोडिंग!