शायद आपको Axios की ज़रूरत नहीं।
फ़ेच API मददके लिए!
आपको शायद Axios की ज़रूरत न पड़े
यह Axios (https://www.npmjs.com/package/axios) पर कोई हमला नहीं है।
बल्कि, यह fetch API के समर्थन के लिए एक वकालत है, जो अब काफी सक्षम हो गया है। 🦄
अवलोकन
यह लेख उन “ग़ायब” fetch कोड स्निपेट्स और सामान्य उपयोग‑केसेज़ का संग्रह है जिसे मैं आसान से नहीं मिलता हूँ।
आपका उपयोग‑केस सूचीबद्ध नहीं है? मुझे बताइए ✉️
फ़ीचर तुलना
| fetch | axios | request | |
|---|---|---|---|
| Intercept request and response | ✅ | ✅ | ✅ |
| Transform request and response data | ✅ | ✅ | ✅ |
| Cancel requests | ✅ | ✅ | ❌ |
| Automatic transforms for JSON data | manual helpers | ✅ | ✅ |
| Client side support for protecting against XSRF | ✅ | ✅ | ✅ |
| Progress | ✅ | ✅ | ✅ |
| Streaming | ✅ | ✅ | ✅ |
| Redirects | ✅ | ✅ | ✅ |
जब मैंने यह लेख लिखना शुरू किया (अंतिम बार 2018, 2024 में अपडेट) तो मैंने सोचा था कि अंत में एक मिश्रित चेक‑बॉक्स तालिका होगी। निश्चित रूप से कुछ विशेष उपयोग मामलों होते हैं जो axios, request, r2, superagent, got आदि को जायज ठहराते हैं।
खैर, जैसा कि बाद में पता चला, मैंने थर्ड‑पार्टी HTTP लाइब्रेरीज़ की आवश्यकता को अधिक आँका।
fetch को कई सालों से (जटिल कार्यों सहित: फ़ाइल अपलोड और त्रुटि/पुनः‑प्रयास समर्थन) इस्तेमाल करने के बावजूद मैं अभी भी fetch की क्षमताओं और सीमाओं को लेकर कुछ धारणाएँ रखता था।
नेटिव fetch स्वचालित रूप से JSON प्रतिक्रियाओं को पार्स नहीं करता और न ही JSON अनुरोध बॉडी को स्ट्रिंगिफ़ाई करता है। आपको प्रतिक्रिया पर response.json() कॉल करना पड़ता है और अनुरोध भेजते समय JSON.stringify() का उपयोग करना पड़ता है। इस ergonomics के मामले में Axios अभी भी बेहतर है; fetch का तर्क यह है कि एक छोटा हेल्पर अक्सर इस अंतर को पाट देता है।
ठीक है, अब देखते हैं fetch क्या‑क्या कर सकता है…
Fetch Recipes
URL से JSON प्राप्त करें
fetch('https://api.github.com/orgs/nodejs') .then(response => response.json()) .then(data => { console.log(data) // result from `response.json()` above }) .catch(error => console.error(error))कस्टम हेडर्स
fetch('https://api.github.com/orgs/nodejs', { headers: new Headers({ 'User-agent': 'Mozilla/4.0 Custom User Agent' })}).then(response => response.json()).then(data => { console.log(data)}).catch(error => console.error(error))HTTP त्रुटि संभालना
const isOk = response => response.ok ? response.json() : Promise.reject(new Error('Failed to load data from server'))
fetch('https://api.github.com/orgs/nodejs') .then(isOk) // <= Use `isOk` function here .then(data => { console.log(data) // Prints result from `response.json()` }) .catch(error => console.error(error))CORS उदाहरण
CORS मुख्यतः सर्वर पर जाँच किया जाता है — इसलिए सर्वर‑साइड पर आपका कॉन्फ़िगरेशन सही होना चाहिए।
credentials विकल्प यह नियंत्रित करता है कि आपके कूकीज़ स्वचालित रूप से शामिल हों या नहीं।
fetch('https://api.github.com/orgs/nodejs', { credentials: 'include', // Useful for including session ID (and, IIRC, authorization headers)}).then(response => response.json()).then(data => { console.log(data) // Prints result from `response.json()`}).catch(error => console.error(error))JSON पोस्ट करना
postRequest('http://example.com/api/v1/users', {user: 'Dan'}) .then(data => console.log(data)) // Result from the `response.json()` call
function postRequest(url, data) { return fetch(url, { credentials: 'same-origin', // 'include', default: 'omit' method: 'POST', // 'GET', 'PUT', 'DELETE', etc. body: JSON.stringify(data), // Use correct payload (matching 'Content-Type') headers: { 'Content-Type': 'application/json' }, }) .then(response => response.json()) .catch(error => console.error(error))}HTML <form> पोस्ट करना
postForm('http://example.com/api/v1/users', 'form#userEdit') .then(data => console.log(data))
function postForm(url, formSelector) { const formData = new FormData(document.querySelector(formSelector))
return fetch(url, { method: 'POST', // 'GET', 'PUT', 'DELETE', etc. body: formData // a FormData will automatically set the 'Content-Type' }) .then(response => response.json()) .catch(error => console.error(error))}फ़ॉर्म एन्कोडेड डेटा
application/x-www-form-urlencoded कंटेंट‑टाइप के साथ डेटा पोस्ट करने के लिए हम URLSearchParams का उपयोग करके डेटा को क्वेरी स्ट्रिंग की तरह एन्कोड करेंगे।
उदाहरण के लिए, new URLSearchParams({a: 1, b: 2}) का परिणाम a=1&b=2 होगा।
postFormData('http://example.com/api/v1/users', {user: 'Mary'}) .then(data => console.log(data))
function postFormData(url, data) { return fetch(url, { method: 'POST', // 'GET', 'PUT', 'DELETE', etc. body: new URLSearchParams(data), headers: new Headers({ 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8' }) }) .then(response => response.json()) .catch(error => console.error(error))}फ़ाइल अपलोड करना
postFile('http://example.com/api/v1/users', 'input[type="file"].avatar') .then(data => console.log(data))
function postFile(url, fileSelector) { const formData = new FormData() const fileField = document.querySelector(fileSelector)
formData.append('username', 'abc123') formData.append('avatar', fileField.files[0])
return fetch(url, { method: 'POST', // 'GET', 'PUT', 'DELETE', etc. body: formData // Coordinate the body type with 'Content-Type' }) .then(response => response.json()) .catch(error => console.error(error))}कई फ़ाइलें अपलोड करना
multiple एट्रिब्यूट के साथ एक फ़ाइल अपलोड एलिमेंट सेट अप करें:
<input type='file' multiple class='files' name='files' />फिर इसे कुछ इस तरह उपयोग करें:
postFile('http://example.com/api/v1/users', 'input[type="file"].files') .then(data => console.log(data))
function postFile(url, fileSelector) { const formData = new FormData() const fileFields = document.querySelectorAll(fileSelector)
// Add all files to formData Array.prototype.forEach.call(fileFields.files, f => formData.append('files', f)) // Alternatively for PHPeeps, use `files[]` for the name to support arrays // Array.prototype.forEach.call(fileFields.files, f => formData.append('files[]', f))
return fetch(url, { method: 'POST', // 'GET', 'PUT', 'DELETE', etc. body: formData // Coordinate the body type with 'Content-Type' }) .then(response => response.json()) .catch(error => console.error(error))}टाइमआउट्स
यहाँ एक सामान्य Promise टाइमआउट है, जो “Partial Application” पैटर्न का उपयोग करता है। यह किसी भी Promise इंटरफ़ेस के साथ काम करेगा। आप द्वारा प्रदान किए गए प्रॉमिस चेन में बहुत अधिक काम न करें; वह लगातार चलता रहेगा—और किसी भी विफलता से दीर्घकालिक मेमोरी लीक्स उत्पन्न हो सकते हैं।
function promiseTimeout(msec) { return promise => { const timeout = new Promise((yea, nah) => setTimeout(() => nah(new Error('Timeout expired')), msec)) return Promise.race([promise, timeout]) }}
promiseTimeout(5000)(fetch('https://api.github.com/orgs/nodejs')) .then(response => response.json()) .then(data => { console.log(data) // Prints result from `response.json()` in getRequest }) .catch(error => console.error(error)) // Catches any timeout (or other failure)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Alternative example:fetchTimeout(5000, 'https://api.github.com/orgs/nodejs') .then(console.log)// Alternative implementation:function fetchTimeout(msec, ...args) { return raceTimeout(fetch(...args))
function raceTimeout(promise) { const timeout = new Promise((yea, nah) => setTimeout(() => nah(new Error('Timeout expired')), msec)) return Promise.race([promise, timeout]) }}और एक अधिक जटिल उदाहरण, जिसमें एक ट्रैकिंग फ़्लैग __timeout शामिल है ताकि आप किसी भी महंगे कार्य को इंटरसेप्ट कर सकें।
function promiseTimeout(msec) { return (promise) => { let isDone = false promise.then(() => isDone = true) const timeout = new Promise((yea, nah) => setTimeout(() => { if (!isDone) { promise.__timeout = true nah(new Error('Timeout expired')) } }, msec)) return Promise.race([promise, timeout]) }}
promiseTimeout(5000)(fetch('https://api.github.com/orgs/nodejs')).then(response => response.json()).then(data => { console.log(data) // Prints result from `response.json()` in getRequest}).catch(error => console.error(error))डाउनलोड प्रोग्रेस हेल्पर
अपलोड प्रोग्रेस वर्तमान में Chrome के बाहर थोड़ा बगgy है।
प्रोग्रेस हैंडलर नीचे दिखाया गया तकनीक क्लोजर में fetch कॉल को लपेटने से बचाता है 👍
progressHelper का इंटरफ़ेस इस प्रकार है (स्रोत नीचे उपलब्ध है)
const progressHelper = require('./progressHelper.js')
const handler = ({loaded, total}) => { console.log(`Downloaded ${loaded} of ${total}`)}// handler args: ({ loaded = Kb, total = 0-100% })const streamProcessor = progressHelper(handler)// => streamProcessor is a function for use with the response _stream_अब एक उपयोग उदाहरण देखें:
// The progressHelper could be inline w/ .then() below...const streamProcessor = progressHelper(console.log)
fetch('https://fetch-progress.anthum.com/20kbps/images/sunrise-progressive.jpg') .then(streamProcessor) // note: NO parentheses because `.then` needs to get a function .then(response => response.blob()) .then(blobData => { // ... set as base64 on an <img src="base64..."> })एक पुन: उपयोग योग्य इमेज डाउनलोडर getBlob() जैसा दिख सकता है:
const getBlob = url => fetch(url) .then(progressHelper(console.log)) // progressHelper used inside the .then() .then(response => response.blob())वैसे, Blob एक Binary Large Object है।
नीचे दिए गए 2 उपयोग पैटर्न में से एक चुनना महत्वपूर्ण है (वे कार्यात्मक रूप से समान हैं):
// OPTION #1: no temp streamProcessor varfetch(...) .then(progressHelper(console.log))
// ⚠️ OR️ ️⚠️
// OPTION #2: define a `streamProcessor` to hold our console loggerconst streamProcessor = progressHelper(console.log)fetch(...) .then(streamProcessor)मेरी पसंद Option #1 है। हालांकि, आपके स्कोप डिज़ाइन के आधार पर आपको Option #2 उपयोग करना पड़ सकता है।
अंत में, इस रेसिपी का अंतिम भाग, हमारा progressHelper प्रस्तुत है:
स्रोत: प्रोग्रेस हेल्पर
function progressHelper(onProgress) { return (response) => { if (!response.body) return response
let loaded = 0 const contentLength = response.headers.get('content-length') const total = !contentLength ? -1 : parseInt(contentLength, 10)
return new Response( new ReadableStream({ start(controller) { const reader = response.body.getReader() return read()
function read() { return reader.read() .then(({ done, value }) => { if (done) return void controller.close() loaded += value.byteLength onProgress({ loaded, total }) controller.enqueue(value) return read() }) .catch(error => { console.error(error) controller.error(error) }) } } }) ) }}धन्यवाद: विशेष धन्यवाद Anthum Chris को और उनके शानदार Progress+Fetch PoC को यहाँ दिखाया गया है
रिकर्सिव रीट्राय हेल्पर
/** * A **Smarter** retry wrapper with currying! */function retryCurry(fn, retriesLeft = 5) { const retryFn = (...args) => fn(...args) .catch(err => retriesLeft > 0 ? retryFn(fn, retriesLeft - 1) : Promise.reject(err) }) return retryFn}
const getJson = (url) => fetch(url) .then(response => response.json())
// Usageconst retryGetJson = retryCurry(getJson, 3);
// Now you can pass any arguments through to your function!retryGetJson('https://api.github.com/orgs/elite-libs') .then(console.log) .catch(console.error)/** Basic retry wrapper for Promises */function retryPromise(fn, retriesLeft = 5) { return fn() .catch(err => retriesLeft > 0 ? retryPromise(fn, retriesLeft - 1) : Promise.reject(err) })}
const getJson = (url) => fetch(url) .then(response => response.json())
// Usageretry(() => getJson('https://api.github.com/orgs/elite-libs')) .then(console.log) .catch(console.error)HTTP रीडायरेक्ट्स को संभालना
const checkForRedirect = (response) => { // Check for temporary redirect (307), or permanent (308) if (response.status === 307 || response.status === 308) { const location = response.headers.get('location') if (!location) { return Promise.reject(new Error('Invalid HTTP Redirect! No Location header.')); } // You can change the behavior here to any custom logic: // e.g. open a "confirm" modal, log the redirect url, etc. return fetch(location) // Bonus: this will handle recursive redirects ✨ .then(checkForRedirect) } return response};
fetch('https://api.github.com/orgs/elite-libs') // Next line will handle redirects .then(checkForRedirect) .then(response => response.json()) .then(console.log) .catch(console.error)fetch अनुरोध को रद्द करना
const httpWithTimeout = (timeout = 5000, url) => { const controller = new AbortController(); // Set an Nsec cancellation timeout const timer = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal }) .then(response => { clearTimeout(timer); // not required but closes open ref return response.text(); }).then(text => { console.log(text); });}अनुकूलता
2022 तक, fetch API सभी आधुनिक ब्राउज़रों में व्यापक रूप से समर्थित है (caniuse.com पर देखें) और NodeJS v18+ के नवीनतम संस्करणों में भी।
यदि आपको IE का समर्थन करना है, तो आप github/fetch पैकेज के साथ fetch को पॉलीफ़िल कर सकते हैं (ब्राउज़र समर्थन देखें). यह IE8 तक पीछे तक जा सकता है (IE8 के लिए fetch देखें) — परिणाम अलग‑अलग हो सकते हैं।
पुराने NodeJS संस्करण fetch API को node-fetch पैकेज के साथ उपयोग कर सकते हैं:
npm install node-fetchपॉलीफ़िल + node-fetch के बाद: 99.99 % संगत ✅
कृपया यदि आपके पास अन्य उपयोग मामलों हैं तो मुझे ट्वीट करें। ❤️