اگر قصد داریم تا دادهها را از یک API لود کنیم Fetch کردن بهترین راه برای انجام این کار در جاوااسکریپت است. در ابتدا ممکن است Fetch API ساده به نظر برسد، اما هر چه بیشتر از آن استفاده کنیم متوجه خواهیم شد که پیچیدگی زیادی دارد. در این مقاله به اصول Fetch کردن و موارد استفاده پیشرفتهتر برای آن میپردازیم، در نهایت مشکلات رایجی را که توسعهدهندگان ممکن است با آنها مواجه شوند را باهم بررسی میکنیم.
Fetch API در جاوااسکریپت یک API مبتنی بر promise است، بنابراین اگر با promiseها آشنا نیستید مطالعه مقاله ساخت promise در جاوااسکریپت میتواند مفید باشد.
سادهترین راه برای فراخوانی Fetch API این است که فقط یک URL به تابع fetch
ارسال کنیم.
fetch("https://jsonplaceholder.typicode.com/users")
این تابع یک promise حاوی دادههای response را برمیگرداند. این دادههای response حاوی ویژگیهایی برای وضعیت پاسخ و همچنین روشهایی برای تبدیل دادههای response خام به JSON، متن یا فرمتهای دیگر است.
fetch("https://jsonplaceholder.typicode.com/users") .then(res => { console.log(res.ok) // true console.log(res.status) // 200 return res.json() })
کد return res.json()
در مثال بالا متد json
را در پاسخ ما فراخوانی میکند و آن را از تابع .then
برمیگرداند. این کار به این دلیل است که متد json
نیز promiseای را برمیگرداند که دادههای JSON را از پاسخ ما ارزیابی میکند. میتوانیم .then
دوم را زنجیرهای کنیم تا دادهها را از متد json
دریافت کنیم.
fetch("https://jsonplaceholder.typicode.com/users") .then(res => res.json()) .then(data => console.log(data)) // [{ userOne }, { userTwo }, ...]
اگر دادهها را از یک JSON api واکشی کنیم، بیشتر درخواستهای fetch ما به این شکل خواهند بود. ابتدا URL را fetch میکنیم، سپس پاسخ را به JSON تبدیل میکنیم و در نهایت از دادهها در .then
نهایی استفاده میکنیم.
در این بخش درمورد برخی از کاربردهای Fetch صحبت خواهیم کرد اما اغلب اوقات برای پیکربندی آن باید گزینههای بیشتری را برای Fetch ارسال کنیم. تابع fetch
یک پارامتر دومی که آبجکت هست را میگیرد که شامل لیست بزرگی از گزینهها میباشد.
در حالی که چندین گزینه وجود دارد که میتوانیم از آنها صرف نظر کنیم اما تعدادی نیز هستند که بیشتر از بقیه مورد استفاده قرار خواهیم داد.
method
تا کنون رایجترین گزینه مورد استفاده، method
است. این گزینه به ما اجازه میدهد تا تعیین کنیم که کدام فعل HTTP را میخواهیم استفاده کنیم (GET، POST، PUT، DELETE و غیره).
fetch("https://jsonplaceholder.typicode.com/users/2", { method: "DELETE" })
body
اگر متد را تغییر دهیم، به احتمال زیاد باید دادهها را همراه با درخواست خود ارسال کنیم. اینجاست که گزینه body
وارد عمل میشود. body
آبجکت نمیپذیرد، بنابراین اگر میخواهیم JSON را به API منتقل کنیم، ابتدا باید آن را به یک رشته تبدیل کنیم.
fetch("https://jsonplaceholder.typicode.com/users", { method: "POST", body: JSON.stringify({ name: "Kyle" }) })
headers
اکنون انجام کارهای بالا ممکن است مانند همه کارهایی باشد که باید انجام دهیم تا JSON را به یک API منتقل کنیم، اما در واقع اینطور نیست و تابع به درستی کار نخواهد کرد. دلیل آن این است که ما باید headerهای مناسبی را تنظیم کنیم تا به API بگوییم که در حال ارسال اطلاعات JSON هستیم. گزینه header
این امکان را به ما میدهد تا هر هدر HTTP را که میخواهیم تنظیم کنیم.
fetch("https://jsonplaceholder.typicode.com/users", { method: "POST", body: JSON.stringify({ name: "Kyle" }), headers: { "Content-Type": "application/json" } })
قطعه کد بالا همان کاری است که باید انجام دهیم تا JSON را به یک API منتقل کنیم.
سه گزینه بالا همان چیزی است که ما برای ۹۰ درصد نیازهای خود به fetch کردن دادهها از آنها استفاده خواهیم کرد، اما چند گزینه پیشرفته نیز وجود دارد که باید آنها را بدانیم.
mode
گزینه mode
به ما این امکان را میدهد تا تعیین کنیم که درخواست باید یک درخواست cors
، no-cors
یا same-origin
باشد. بهطور پیشفرض، همه درخواستهای fetch بهعنوان درخواستهای cors
تنظیم میشوند تا بتوانیم به منابع دیگر مبدا دسترسی داشته باشیم، اما اگر بخواهیم میتوانیم fetch را مجبور کنیم که فقط درخواستهای same-origin
را مجاز کند. در این صورت اگر بخواهیم URLای که در همان مبدا نیست را fetch کنیم، با خطا مواجه میشویم.
fetch("https://jsonplaceholder.typicode.com/users", { mode: "same-origin" }).catch(e => console.error(e))
credentials
گزینه دیگری که با cors
سروکار دارد، credentials
است. این گزینه میتواند مقادیر omit
، same-origin
و یا include
را داشته باشد و تعیین میکند که آیا Fetch API کوکیها و سایر اطلاعات مبتنی بر اعتبار را دریافت میکند یا خیر. omit
هیچ credentials
ای ارسال یا دریافت نمیکند. same-origin
فقط credentials
ها را از همان URL ارسال یا دریافت میکند و include
همه credentials
ها را از هر URLای ارسال یا دریافت میکند.
این گزینه بهطور پیشفرض روی same-origin
تنظیم شده است.
fetch("https://jsonplaceholder.typicode.com/users", { credentials: "include" })
signal
آخرین گزینه پیشرفتهای که باید با آن آشنا شویم گزینه signal
است. این گزینه یک AbortSignal
را میگیرد که میتواند برای لغو درخواست fetch کردن دادهها استفاده شود.
const controller = new AbortController() fetch("https://jsonplaceholder.typicode.com/users", { signal: controller.signal }).catch(e => console.error(e.name)) // AbortError controller.abort()
همانطور که در کد بالا میبینیم این مورد کمی پیچیدهتر از گزینههای دیگر است. ابتدا باید یک AbortController
جدید ایجاد کنیم. این کنترلر دارای یک ویژگی signal
است، همان چیزی که به گزینه signal
منتقل میکنیم. کنترلر همچنین دارای یک متد abort
میباشد که در صورت فراخوانی، درخواست fetch با signal
مربوط به آن لغو میشود. این کار باعث میشود که پرامیس fetch با یک استثنا AborError
رد شود.
یکی از مواردی که در fetch API ممکن است گیجکننده باشد این است که اگر پاسخ HTTP 400، ۵۰۰ یا هر خطای دیگری را دریافت کنیم، خطایی برای ما ایجاد نمیشود. تنها راهی که میتوانیم تشخیص دهیم که آیا یک درخواست شکست خورده است یا خیر بررسی ویژگی ok
پاسخ است.
fetch("https://jsonplaceholder.typicode.com/users/-1") .then(res => { console.log(res.ok) // false console.log(res.status) // 404 })
به دلیل این تفاوتهای ظریف، بهتر است کد را طوری بنویسیم تا زمانی که وضعیت پاسخ خوب نیست، درخواستی انجام نشود.
fetch("https://jsonplaceholder.typicode.com/users/-1") .then(res => { if (res.ok) return res.json() return Promise.reject(res) }) .then(data => console.log(data)) .catch(res => console.error(res.status)) // 404
اگر پاسخ بدون مشکل باشد، تمام کد را به صورت عادی نگه میداریم، در غیر این صورت یک promise رد شده را که حاوی پاسخ است برمیگردانیم تا بتوانیم آن را در یک .catch
مدیریت کنیم.
همچنین گاهی اوقات میتوانیم یک گام دیگر فراتر برویم و تابع fetch سفارشی خود را ایجاد کنیم.
function jsonFetch(url, { body, headers, ...options } = {}) { return fetch(url, { headers: { "Content-Type": "application/json", ...headers } body: JSON.stringify(body) ...options }) .then(res => { if (res.ok) return res.json() return Promise.reject(res) }) .then(res => res.json()) }
این تابع سفارشی از تمام کدهای اضافی که برای ارسال دادههای JSON نیاز داریم مراقبت میکند و همچنان به ما این امکان را میدهد تا از همه گزینههای سفارشی fetch استفاده کنیم. همچنین throwing errorها را برای مواردی مانند ۴۰۴ کنترل میکند.
حال اگر احساس میکنیم که انجام چنین کاری بسیار دردسرساز است، میتوانیم از کتابخانهای مانند axios استفاده کنیم که کار کردن با API را به شدت ساده میکند.
Fetch API یک ابزار قدرتمند در جاوااسکریپت است که به راحتی میتوان کار کردن با آن را شروع کرد، اما شامل بسیاری از گزینههای پیشرفته برای همه مواردی است که در طول کار کردن با آن نیاز پیدا خواهیم کرد.
دیدگاهها: