البرمجة

استخدام واجهة Fetch في JavaScript

الواجهة البرمجية fetch في JavaScript: كيفية الاستخدام والتفاصيل التقنية

في عصر الويب الحديث، يعتبر التعامل مع البيانات من أهم العمليات التي تتم بين العميل والخادم. ومن أجل تسهيل هذا التواصل، تم توفير العديد من الأدوات والمكتبات، ومن بينها الواجهة البرمجية fetch في JavaScript. تعتبر هذه الواجهة واحدة من أكثر الأساليب استخدامًا لطلب البيانات من الخوادم عبر بروتوكول HTTP، وتتميز بمرونتها وبساطتها مقارنة بأساليب أخرى كانت تستخدم في الماضي مثل XMLHttpRequest. في هذا المقال، سنتناول بالشرح الوافي كيفية استخدام fetch، مزاياها، تفاصيلها التقنية، والأمثلة العملية التي تتيح للمطورين التفاعل مع بيانات الخادم بسهولة وفاعلية.

1. ما هي واجهة fetch؟

الواجهة البرمجية fetch هي واجهة توفرها JavaScript للتفاعل مع الشبكة عن طريق إرسال طلبات HTTP إلى الخادم (server) واستلام البيانات بشكل غير متزامن (asynchronous). يمكن استخدامها لاستلام البيانات بتنسيقات مختلفة مثل JSON، نصوص HTML، صور، أو حتى ملفات صوتية وفيديو. يتميز fetch بكونه يعتمد على الـ Promises في JavaScript، مما يسهل التعامل مع العمليات غير المتزامنة مقارنة بالطرق القديمة التي كانت تعتمد على الكولباك (callback).

2. كيف يعمل fetch؟

عند استخدام fetch، يتم إرسال طلب إلى الخادم عبر الإنترنت باستخدام بروتوكول HTTP، وعادة ما يكون هذا الطلب من نوع GET أو POST، لكن يمكن تخصيصه ليناسب جميع أنواع الطلبات HTTP مثل PUT أو DELETE أو PATCH. على الرغم من أن الواجهة قد تكون بسيطة، فإن الطريقة التي يتم بها تنفيذ الطلبات ومعالجة الردود تتضمن عددًا من المفاهيم المهمة مثل التعامل مع الـ Promises، وإدارة الاستثناءات (errors)، ومعالجة الردود المختلفة من الخادم.

3. بنية الطلب باستخدام fetch

أبسط طريقة لاستخدام fetch هي ببساطة توفير عنوان URL المطلوب الوصول إليه. في أبسط شكل، سيبدو الأمر كالتالي:

javascript
fetch('https://api.example.com/data') .then(response => response.json()) // تحويل الرد إلى JSON .then(data => console.log(data)) // التعامل مع البيانات .catch(error => console.error('Error:', error)); // التعامل مع الأخطاء

في هذا المثال:

  • fetch() يتم استدعاؤه مع عنوان URL الذي يحتوي على المورد (resource) الذي تريد الحصول عليه.

  • then(response => response.json()) يقوم بتحويل استجابة الخادم إلى تنسيق JSON باستخدام response.json(). هذه عملية غير متزامنة أيضًا.

  • في حالة النجاح، يتم التعامل مع البيانات باستخدام الدالة then().

  • في حالة حدوث أي خطأ، يتم التعامل مع الاستثناءات باستخدام catch().

4. أنواع الطلبات في fetch

بافتراض أن الطلب الأساسي هو من نوع GET، يمكن تعديل نوع الطلب لتشمل أنواع أخرى مثل POST أو PUT أو DELETE، على النحو التالي:

طلب POST
javascript
fetch('https://api.example.com/data', { method: 'POST', // تحديد نوع الطلب headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'John Doe', age: 30 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));

في هذا المثال، يقوم العميل بإرسال بيانات إلى الخادم باستخدام طريقة POST. يتم تحديد رؤوس الطلب (headers) وتحديد نوع المحتوى (Content-Type) ليكون JSON. يتم تحويل البيانات المرسلة إلى JSON باستخدام JSON.stringify() وإضافتها إلى الحقل body.

طلب PUT
javascript
fetch('https://api.example.com/data/1', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'John Smith', age: 32 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));

يتم استخدام PUT لتحديث مورد معين على الخادم. يتم إرسال البيانات المحدثة في الـ body.

5. معالجة استجابة الخادم

عند إرسال طلب باستخدام fetch، يتم التعامل مع استجابة الخادم بشكل غير متزامن. الاستجابة تكون غالبًا عبارة عن كائن من النوع Response، والذي يحتوي على معلومات حول حالة الطلب، مثل الكود الخاص بالاستجابة (مثل 200 للطريقة الناجحة أو 404 للصفحة غير الموجودة).

إليك طريقة التعامل مع الرد وتحديد حالته:

javascript
fetch('https://api.example.com/data') .then(response => { if (!response.ok) { // تحقق من حالة الاستجابة throw new Error('Network response was not ok'); } return response.json(); }) .then(data => console.log(data)) .catch(error => console.error('There was a problem with your fetch operation:', error));

في هذا المثال:

  • response.ok يتحقق مما إذا كانت الاستجابة ناجحة. إذا كانت false، سيتم رمي خطأ.

  • إذا كانت الاستجابة ناجحة، يتم تحويل البيانات إلى JSON باستخدام response.json().

6. التعامل مع الأخطاء في fetch

واحدة من المزايا الكبيرة لـ fetch هي قدرتها على التعامل مع الأخطاء بشكل مريح. عندما يحدث خطأ في إرسال الطلب أو في عملية تحويل البيانات، يتم رمي استثناء (exception) يمكن التقاطه باستخدام catch().

من المهم أن نفهم أن fetch لا يعتبر أي حالة من حالات HTTP غير 2xx خطأ بشكل افتراضي، مما يعني أنه حتى لو كانت الاستجابة تحتوي على كود حالة 404 أو 500، فإن fetch لن يرمِ خطأ تلقائيًا. يجب أن يتعامل المطور مع ذلك يدويا باستخدام الكود الذي أشرنا إليه سابقًا.

7. التعامل مع البيانات بتنسيقات متعددة

قد لا تكون جميع البيانات التي تتلقاها من الخادم في تنسيق JSON، بل قد تكون نصية أو صورة أو ملفًا آخر. لتوضيح هذه العمليات:

استلام نص عادي:
javascript
fetch('https://example.com/textfile.txt') .then(response => response.text()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));
استلام صورة:
javascript
fetch('https://example.com/image.jpg') .then(response => response.blob()) // تحويل الصورة إلى blob .then(imageBlob => { const imageObjectURL = URL.createObjectURL(imageBlob); document.querySelector('img').src = imageObjectURL; }) .catch(error => console.error('Error:', error));
استلام ملف JSON:
javascript
fetch('https://api.example.com/data.json') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));

8. إرسال الطلبات المتزامنة باستخدام Promise.all

في بعض الأحيان، قد تحتاج إلى إرسال عدة طلبات fetch في وقت واحد. باستخدام Promise.all()، يمكنك الانتظار حتى تكتمل جميع هذه الطلبات، ومن ثم معالجة الردود جميعها معًا:

javascript
Promise.all([ fetch('https://api.example.com/data1'), fetch('https://api.example.com/data2') ]) .then(responses => Promise.all(responses.map(response => response.json()))) .then(data => console.log(data)) .catch(error => console.error('Error:', error));

9. الإنهاء المبكر للطلبات باستخدام AbortController

في بعض الحالات، قد تحتاج إلى إلغاء طلب قبل أن يتم استلام الرد من الخادم. يتم تحقيق ذلك باستخدام AbortController، وهو أداة توفرها JavaScript لإلغاء الطلبات غير الضرورية.

javascript
const controller = new AbortController(); const signal = controller.signal; fetch('https://api.example.com/data', { signal }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => { if (error.name === 'AbortError') { console.log('Request was aborted'); } else { console.error('Error:', error); } }); // إلغاء الطلب بعد 5 ثوان setTimeout(() => controller.abort(), 5000);

10. استنتاجات

توفر واجهة fetch طريقة مرنة وقوية للتفاعل مع البيانات عبر الإنترنت في JavaScript. بفضل بساطتها واعتمادها على Promises، تجعل fetch من السهل التعامل مع العمليات غير المتزامنة وتنفيذ عمليات الشبكة المتقدمة بسهولة. في الوقت نفسه، توفر fetch دعمًا لمعظم أنواع البيانات، مثل JSON والنصوص والصور، مما يجعلها مناسبة لمجموعة واسعة من التطبيقات.