مفهوم الـ API

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 10 دقائق

المقدمة

اهلا بكم جميعًا، سأحاول هنا ان أقوم بشرح مفهوم الـ API وكيفية استخدامه
سيكون هناك درس منفصل لكيفية عمل وبرمجة الـ API إن شاء الله

سنستخدم لغة javascript للتطبيق العملي لا اكثر، لكن كل ما سنشرحه هنا من أمور ومفاهيم يمكنكم عمله في أي لغة اخرى

ما هو الـ API ؟

الـ API اختصار لـ Application Programming Interface أي واجهة برمجة التطبيقات
وهي تعمل كوسيط لتبادل البيانات ما بين مصدر ما يمتلك البيانات ومستخدم، عميل، مبرمج، او شركة .... يريد الحصول على تلك البيانات

فعلى سبيل المثال ان كان لدينا مصدر لديه قاعدة بيانات database
فإن هذا المصدر سيسمح للمطورين او أي عميل بالوصول لبعض تلك البيانات لكن

هذا الوسيط هو الـ API هو واجهتك البرمجية للوصول لبيانات هذا المصدر

+----------------+             +----------------+
|                | <---------- |                |
|     المصدر     |     API     |     العميل     |
|                | ----------> |                |
+----------------+             +----------------+
API الـ العميل يطلب البيانات من مصدر معين عن طريق

الـ API يكون مجرد وسيط يجلب لك معلومات من قاعدة بيانات او وسيط لخدمات معينة تقدمها لك بعض الشركات والمواقع
مثل الـ youtube, twitter, google و github جميعهم لديهم API مختلف يقدم بعض الخدمات او المعلومات

مثال نادل المطعم

المثال المشهور لشرح مفهوم الـ API هو مثال نادل المطعم
دعنا نشبه المصدر الذي نريد الحصول على البيانات منه بالمطعم
وانت هو الزبون الذي يريد البيانات، أنت لن تستطيع ان تطلب ما تشاء بل أنت فقط تختار من قائمة الطعام التي يحددها لك المطعم
وعندما تختار ما تريد يذهب النادل إلى الطباخ ثم يجهز الطباخ لك الوجبة وعند انتهائها يأتي النادل لك ومعه طلبك
انت هنا تستطيع أخذ الوجبة وتفعل ما تريد بها

+----------------+              +----------------+
|                | <----------- |                |
|     الزبون     |    النادل    |     المطعم     |
|                | -----------> |                |
+----------------+              +----------------+
    الزبون يطلب الطعام من المطعم عن طريق النادل

هذا هو مفهوم الـ API تخيل ان النادل هو الـ API وقائمة الطعام هي البيانات التي يحددها المصدر ليشاركها وتصبح متاحة للجميع
لكن لا يأخذون البيانات بشكلها العادي بل الطباخ يجهزها لك بشكل وشروط معينة لتستخدمها بهذا الشكل
المطعم هو المصدر او الـ Server الذي يتعامل مع الـ database وينظم لك البيانات بشروط معينة يحددها المصدر وشكل معين ليرسلها للعميل الذي طلبها

معنى هذا انك لا تستطيع أخذ ما تريد والمصدر هو من يحدد ماذا سيعطيك وكيف سيعطيك وسيعطيك ذلك عن طريق API

ملخص الأمر ببساطة

  1. العميل يرسل طلب للـ server
  2. الـ API يقوم بجلب البيانات من الـ Server
  3. الـ API يقوم بإرسال البيانات إلى العميل
+----------------+    Request    +----------------+
|                | <------------ |                |
|     Server     |      API      |     Client     |
|                | ------------> |                |
+----------------+    Response   +----------------+
      Backend                         Frontend

ما هو الـ JSON ؟

الـ JSON هو اختصار لـ Java Script Object Notation وكما يوحي الاسم فهو متعلق نوعًا ما بلغة javascript لكن هذا لا يعني انه حكر على تلك اللغة فقط
كل ما في الأمر انها بدأت بالنمو عن طريق مفهوم الـ Dictionary القاموس المتواجد في الـ javascript
واصبح يمكنك استعمالها غالبًا في أي لغة في العالم

يستخدم الـ JSON كشكل او نموذج عام ومتعارف عليه بين المواقع والمطورين في تخزين وارسال البيانات ويستخدمها الـ API لإرسال البيانات
وهذا بسبب بساطتها وتنظيمها ويسهل عليك قراءتها والتعامل معها بسلاسة

دعونا نأخذ مثالًا عمليا، نريد ان نخزن بيانات منتج معين وليكن نوع من انواع الهواتف الذكية العالمية
نفتح ملف جديد ونسميه file.json لاحظ ان الامتداد هنا هو json ثم نكتب بياناتنا في شكل JSON

نفتح اقوس متعرجة { } ونكتب داخلها البيانات
عناصر الـ JSON تتكون من key وvalue مفصولة بـ : والـ key دائمًا ما يكون string والـ value يمكن ان يكون أي نوع بيانات

{
  "name": "Redmi 9",
  "brand": "Xiaomi",
  "colors-available": ["gray", "violet", "green"],
  "ram": 4,
  "space": 64,
  "fast-charging": true,
  "water-resistant": false
}

هنا لدينا مجموعة بيانات لمنتج معين موضوعة في شكل JSON في ملف يمكنك من خلال قراءتك له ان تفهم محتواه
فالبيانات مترتبة ومنظمة في هيئة keys وvalues كل عنصر يصف البيانات او القيمة التي لديه

فنحن الآن نعرف ان إسم هذا الهاتف هو Redmi 9 ومن شركة Xiaomi والاوان المتاحة لهذا الهاتف هي الرمادي والبنفسجي والأخضر

كل هذه المعلومات استطعنا استخراجها بسهولة بطريقة منظمة وفوق هذا نستطيع في أي لغة برمجية ان نتعامل مع هذه البيانات بسهولة تامة

تطبيق عملي لاستخدام الـ API

سنقوم بعمل تجربة عملية لكيفية التعامل مع الـ API
ولدينا هنا API أنشأهُ شخص من إندونيسيا يدعى Gading Nasution،
رابط حسابه على github من هنا ورابط مستودع المشروع الخاص بهذا الـ API من هنا
هذا الـ API يضم الأحاديث النبوية الواردة في الكتب التسعة للأحاديث

هذا الـ API يمكننا التعامل معه عن طريق هذا الرابط https://api.hadith.gading.dev/

async function getData() {
  let url = 'https://api.hadith.gading.dev/';
  let obj = await fetch(url);
  let data = await obj.json();

  console.log(data);
}
getData();

ملحوظة: ان كنت لا تعرف التعامل مع الدالة الغير متزامنة Asynchronous function
او كيف تتعامل مع دالة fetch، فأرجوا ان المقالات التالية مثل promise و async-await

سنقوم بكتابة الدالة خاصتنا بشكل اعتيادي ونعطيها الـ url الخاص بالـ API ثم نقوم بعمل fetch له وتحويل البيانات إلى JSON ثم نطبعه
ناتج الطباعة سيكون كالتالي

{
  "maintaner": "Sutan Gading Fadhillah Nasution <[email protected]>",
  "source": "https://github.com/sutanlab/hadith-api",
  "endpoints": {
    "list": {
      "pattern": "https://api.hadith.gading.dev/books",
      "description": "Returns the list of available Hadith Books."
    },
    "hadith": {
      "pattern": "https://api.hadith.gading.dev/books/{name}?range={number}-{number}",
      "example": "https://api.hadith.gading.dev/books/muslim?range=1-150",
      "description": "Returns hadiths by range of number. (Note: For performance reasons, max accepted range: 300)"
    },
    "spesific": {
      "pattern": "https://api.hadith.gading.dev/books/{name}/{number}",
      "example": "https://api.hadith.gading.dev/books/bukhari/52",
      "description": "Returns spesific hadith."
    }
  }
}

هذا هو الرد التي تلقيناه من الـ Server جاء على هيئة JSON
يمكننا ان نتعامل مع هذا الرد كأنه قائمة الطعام الذي احضرها لك النادل API من الطباخ server
كما قلنا فالطباخ لن يعطيك كل البيانات بسهولة، هو سيعطيك البيانات بالشكل والشروط الذي يضعها

حسنًا دعونا نحلل الرد الذي تلقيناه،
سنرى انه يحتوي على بعض البيانات مثل maintaner يحتوي على بيانات صانع هذا الـ API وsource وهو بالطبع رابط مستودع هذا المشروع على github
ثم لدينا endpoints وهو كما يبدو يحتوي على طريقة استخدام هذا API مثل كيفية إحضار الكتب او كيفية تحديد حديث معين وهكذا

على سبيل المثال لإحضار الكتب نضع /books في اخر الرابط وان اردنا حديث معين نكتب إسم الكتاب ثم رقم الحديث في نهاية الرابط هكذا /books/bukhari/52

ملحوظة: الرد الذي جاءنا، من يحدد شكله ومحتواه هو صانع الـ API بنفسه ليعطي بعض البيانات لنا لكيفية التعامل معه
لذا قد يختلف API عن اخر باختلاف صاحبه وكيف يريدنا ان نتعامل معه

دعونا نحضر الكتب الذي يحتويه هذا الـ API بالرابط الذي حدده

async function getData() {
  let url = 'https://api.hadith.gading.dev/books'; // get all books
  let obj = await fetch(url);
  let data = await obj.json();

  console.log(data);
}
getData();

الرد الذي تلقيناه جاء بالشكل التالي

{
  "code": 200,
  "message": "9 books sent.",
  "data": [
    {
      "name": "HR. Abu Daud",
      "id": "abu-daud",
      "available": 4419
    },
    {
      "name": "HR. Ahmad",
      "id": "ahmad",
      "available": 4305
    },
    {
      "name": "HR. Bukhari",
      "id": "bukhari",
      "available": 6638
    },
    {
      "name": "HR. Darimi",
      "id": "darimi",
      "available": 2949
    },
    {
      "name": "HR. Ibnu Majah",
      "id": "ibnu-majah",
      "available": 4285
    },
    {
      "name": "HR. Malik",
      "id": "malik",
      "available": 1587
    },
    {
      "name": "HR. Muslim",
      "id": "muslim",
      "available": 4930
    },
    {
      "name": "HR. Nasai",
      "id": "nasai",
      "available": 5364
    },
    {
      "name": "HR. Tirmidzi",
      "id": "tirmidzi",
      "available": 3625
    }
  ],
  "error": false
}

سترى انه ارسل لك رد يحتوي على الكتب التي لديه وهي تسعه كتب ويعطينا بعض البيانات عن كل كتاب
ان حللنا الرد سنرى انه يضم code وظاهر لدينا انه يساوي 200 فيعني ان الرد ناجح، يمكنك تفقد دلالات هذه الرموز من هنا
ثم لدينا رسالة message تخبرنا انه تم ارسال 9 كتب
ثم لدينا data وهو ما يهمنا هنا فهو يحتوي على أراي، كل عنصر فيها يضم object به معلومات عن كل كتاب مثل الإسم وعدد الاحاديث
ان اردنا الوصول لإسم أول كتاب فسوف نقول data[0].name أي اننا نحضر أول عنوان في الأراي data وهو index 0 ثم نحضر الإسم
وبطبع اخر شيء لدينا في الرد هو error تخبرنا ان حدث خطأ ام لا

تذكر : ان تلك البيانات والمعلومات التي تلقيناها كتبها صاحب الـ API كان يمكنه ان يمنحنا معلومات اقل اواكثر مثل ما يريد
وطبعا كلما كانت المعلومات وافية ومنظمة كلما كان الـ API جيد فعلى سبيل المثال كان يمكنه اخفاء معلومات مثل code, error لكنه لم يفعل

حسنا، انظر كيف سنحضر جميع اسماء الكتب

async function getData() {
  let url = 'https://api.hadith.gading.dev/books';
  let obj = await fetch(url);
  let data = await obj.json();

  let numberOfBooks = data.data.length;
  // the second "data" is a key contain array inside the "data" object

  for (let i = 0; i < 9; i += 1) {
    console.log(data.data[i].name);
    // print every book's name
    // we can write it like this: data["data"][i].name or data["data"][i]["name"]
  }
}
getData();

هكذا سيتم طباعة جميع اسماء الكتب التي معنا بهذا الشكل

HR. Abu Daud
HR. Ahmad
HR. Bukhari
HR. Darimi
HR. Ibnu Majah
HR. Malik
HR. Muslim
HR. Nasai
HR. Tirmidzi

دعونا نحظى بمثال اخير، صاحب الـ API اخبرنا اننا يمكننا جلب أي حديث من أي كتاب بهذا الشكل /books/bukhari/52
دعونا نجرب الأمر

async function getData() {
  let url = 'https://api.hadith.gading.dev/books/bukhari/52';
  let obj = await fetch(url);
  let data = await obj.json();

  console.log(data);
}
getData();

الرد سيكون هكذا

{
  "code": 200,
  "message": "HR. Bukhari No. 52 sent.",
  "data": {
    "name": "HR. Bukhari",
    "id": "bukhari",
    "available": 6638,
    "contents": {
      "number": 52,
      "arab": "حَدَّثَنَا عَبْدُ اللَّهِ بْنُ مَسْلَمَةَ قَالَ أَخْبَرَنَا مَالِكٌ عَنْ يَحْيَى بْنِ سَعِيدٍ عَنْ مُحَمَّدِ بْنِ إِبْرَاهِيمَ عَنْ عَلْقَمَةَ بْنِ وَقَّاصٍ عَنْ عُمَرَأَنَّ رَسُولَ اللَّهِ صَلَّى اللَّهُ عَلَيْهِ وَسَلَّمَ قَالَ الْأَعْمَالُ بِالنِّيَّةِ وَلِكُلِّ امْرِئٍ مَا نَوَى فَمَنْ كَانَتْ هِجْرَتُهُ إِلَى اللَّهِ وَرَسُولِهِ فَهِجْرَتُهُ إِلَى اللَّهِ وَرَسُولِهِ وَمَنْ كَانَتْ هِجْرَتُهُ لدُنْيَا يُصِيبُهَا أَوْ امْرَأَةٍ يَتَزَوَّجُهَا فَهِجْرَتُهُ إِلَى مَا هَاجَرَ إِلَيْهِ",
      "id": "Telah menceritakan kepada kami [Abdullah bin Maslamah] berkata, telah mengabarkan kepada kami [Malik] dari [Yahya bin Sa'id] dari [Muhammad bin Ibrahim] dari [Alqamah bin Waqash] dari [Umar], bahwa Rasulullah shallallahu 'alaihi wasallam bersabda: \"Semua perbuatan tergantung niatnya, dan (balasan) bagi tiap-tiap orang (tergantung) apa yang diniatkan; barangsiapa niat hijrahnya karena Allah dan Rasul-Nya, maka hijrahnya adalah kepada Allah dan Rasul-Nya. Barangsiapa niat hijrahnya karena dunia yang ingin digapainya atau karena seorang perempuan yang ingin dinikahinya, maka hijrahnya adalah kepada apa dia diniatkan.\". "
    }
  },
  "error": false
}

اظنك تستطيع تحليل الرد بنفسك وتستطيع الوصول للترجمة العربية للحديث وطباعته بهذا الشكل

async function getData() {
  let url = 'https://api.hadith.gading.dev/books/bukhari/52';
  let obj = await fetch(url);
  let data = await obj.json();

  console.log(data.data.contents.arab);
}
getData();

الرد سيكون هكذا

حَدَّثَنَا عَبْدُ اللَّهِ بْنُ مَسْلَمَةَ قَالَ أَخْبَرَنَا مَالِكٌ عَنْ يَحْيَى بْنِ سَعِيدٍ عَنْ مُحَمَّدِ بْنِ إِبْرَاهِيمَ عَنْ عَلْقَمَةَ بْنِ وَقَّاصٍ عَنْ عُمَرَ
أَنَّ رَسُولَ اللَّهِ صَلَّى اللَّهُ عَلَيْهِ وَسَلَّمَ قَالَ الْأَعْمَالُ بِالنِّيَّةِ وَلِكُلِّ امْرِئٍ مَا نَوَى فَمَنْ كَانَتْ هِجْرَتُهُ إِلَى اللَّهِ وَرَسُولِهِ فَهِجْرَتُهُ إِلَى اللَّهِ وَرَسُولِهِ
وَمَنْ كَانَتْ هِجْرَتُهُ لدُنْيَا يُصِيبُهَا أَوْ امْرَأَةٍ يَتَزَوَّجُهَا فَهِجْرَتُهُ إِلَى مَا هَاجَرَ إِلَيْهِ

اظنك فهمت الآن بشكل مبدأي ماذا يكون الـ API وكيفية التعامل معه

ملحوظة: شكل وهيئة كل API والمعلومات الذي يعطيها لك وطريقة الرد والعرض صاحب الـ API هو من يحددها
لذا فيجب عليك قبل ان تستخدم أي API عليك قراءة الـ Docs الخاصة به لتعرف كيف يريد صاحب الـ API ان تتعامل معه