Fetch API


Fetch API

يا هلا بالشباب! اليوم بنتكلم عن أداة قوية جداً في عالم الجافاسكريبت اسمها Fetch API. لو كنت بتتعامل مع الـAPIs عشان تجيب بيانات أو ترسلها، فـFetch هو صديقك المفضل. انسى XMLHttpRequest القديم، Fetch أبسط وأحدث وأكثر قوة.

إيش هو الـFetch API؟

باختصار، هو واجهة برمجية حديثة ومبنية على الـPromise في المتصفحات عشان تسوي طلبات شبكة (HTTP requests). يعني تقدر تجيب بيانات من سيرفر، أو ترسل بيانات، أو تحدثها، كل هذا بطريقة سهلة ونظيفة.

ملاحظة: الـFetch API مدمج في المتصفحات الحديثة، وما يحتاج أي مكتبات خارجية زي Axios (رغم إن Axios ممتاز برضه!).

أول طلب: GET بسيط

أسهل طريقة تستخدم فيها Fetch هي عشان تجيب بيانات. كل اللي عليك هو تمرير رابط الـAPI اللي تبغاه.

fetch('https://api.example.com/data')
  .then(response => response.json()) // تحويل الاستجابة إلى JSON
  .then(data => {
    console.log(data); // هنا البيانات جاهزة للاستخدام
  })
  .catch(error => {
    console.error('فيه مشكلة صارت:', error);
  });

شوف كيف الكود بسيط؟ fetch() ترجع Promise. أول .then() تاخذ الاستجابة (response) وتحولها إلى JSON (أو text() أو blob() حسب نوع البيانات). ثاني .then() تاخذ البيانات المحولة وتستخدمها. و.catch() طبعاً عشان نصيد أي أخطاء.

فهم الاستجابات (Responses)

الـresponse اللي تجيك فيها معلومات كثيرة. أهم شيئين: response.ok و response.status.

response.ok: ترجع true لو كان الـHTTP status code بين 200-299. يعني الطلب نجح.

response.status: ترجع رقم الـHTTP status code (مثلاً 200 للنجاح، 404 لعدم وجود المورد، 500 لخطأ في السيرفر).

من المهم جداً إنك تشيك على response.ok قبل ما تحاول تحول الاستجابة لـJSON، لأن لو فيه خطأ في السيرفر (مثلاً 404)، محاولة تحويلها لـJSON ممكن تسبب لك مشكلة.

fetch('https://api.example.com/non-existent-data')
  .then(response => {
    if (!response.ok) {
      // لو كان فيه خطأ في السيرفر، ارمي (throw) خطأ
      throw new Error('فشل في جلب البيانات: ' + response.status);
    }
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('أوه لا! حصل خطأ:', error);
  });

إرسال البيانات: POST Request

لو تبغى ترسل بيانات للسيرفر (مثلاً تسجل مستخدم جديد أو تضيف منتج)، تحتاج تستخدم الـPOST.

هنا لازم تمرر كائن ثاني لـfetch() تحدد فيه الـmethod والـheaders (خاصة Content-Type) والـbody.

const newData = {
  name: 'صالح',
  email: 'saleh@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST', // نوع الطلب
  headers: {
    'Content-Type': 'application/json', // مهم جداً عشان السيرفر يعرف نوع البيانات
  },
  body: JSON.stringify(newData), // تحويل الكائن إلى سترينج JSON
})
  .then(response => {
    if (!response.ok) {
      throw new Error('فشل في إضافة المستخدم: ' + response.status);
    }
    return response.json(); // السيرفر ممكن يرجع بيانات المستخدم المضاف
  })
  .then(user => {
    console.log('تم إضافة المستخدم بنجاح:', user);
  })
  .catch(error => {
    console.error('مشكلة في إضافة المستخدم:', error);
  });

تذكر: في طلبات POST (أو PUT)، الـbody لازم يكون string. عشان كذا نستخدم JSON.stringify() لتحويل كائن الجافاسكريبت إلى سترينج JSON.

طرق HTTP الثانية (PUT, DELETE)

نفس طريقة الـPOST بالضبط، بس تغير قيمة الـmethod:

  • PUT: لتحديث مورد موجود بالكامل.
  • PATCH: لتحديث جزء من مورد موجود.
  • DELETE: لحذف مورد.
// مثال على PUT لتحديث مستخدم
fetch('https://api.example.com/users/123', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'أحمد صالح', email: 'ahmad.saleh@example.com' }),
})
  .then(response => response.json())
  .then(updatedUser => console.log('تم تحديث المستخدم:', updatedUser));

// مثال على DELETE لحذف مستخدم
fetch('https://api.example.com/users/123', {
  method: 'DELETE',
})
  .then(response => {
    if (response.ok) {
      console.log('تم حذف المستخدم بنجاح.');
    } else {
      throw new Error('فشل في حذف المستخدم: ' + response.status);
    }
  })
  .catch(error => console.error('خطأ في الحذف:', error));

الـFetch مع Async/Await (الأسلوب الأنيق)

لو انت من محبين الكود النظيف والقابل للقراءة، async/await راح يخلي استخدام Fetch أسهل بكثير، ويخلي الكود كانه synchronous.

async function getUsers() {
  try {
    const response = await fetch('https://api.example.com/users');
    
    if (!response.ok) {
      throw new Error('فشل في جلب المستخدمين: ' + response.status);
    }
    
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error('مشكلة في جلب المستخدمين:', error);
  }
}

getUsers();

شوف كيف الكود صار خطي أكثر وواضح. الـawait توقف تنفيذ الدالة لين ما الـPromise تنتهي، سواء بالنجاح أو الفشل. ونستخدم try...catch عشان نصيد الأخطاء.

إلغاء الطلبات: AbortController (للمحترفين!)

أحياناً تحتاج تلغي طلب شبكة قيد التنفيذ (مثلاً لو المستخدم غير رأيه وبحث عن شي ثاني قبل ما الطلب الأول يخلص). هنا يجي دور AbortController.

const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/long-running-task', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('تم إلغاء الطلب.');
    } else {
      console.error('خطأ آخر:', error);
    }
  });

// بعد فترة معينة أو عند حدث معين (مثلاً، المستخدم ضغط زر إلغاء)
// controller.abort(); // هذا الكود يلغي الطلب

AbortController مفيد جداً في تطبيقات الـSPA (Single Page Applications) عشان تتجنب مشاكل الـ"Race Conditions" وتوفر موارد الشبكة.

وبكذا نكون غطينا أساسيات Fetch API وأكثر. هو أداة لا غنى عنها لأي مطور ويب بيتعامل مع الـAPIs. تمرن عليها وراح تشوف كيف بتسهل عليك شغلك كثير. بالتوفيق!