دليل كامل لفهم كل شيء عن الـ APIs مع أمثلة
٢٦ مارس ٢٠٢٦
ملخص
تسمح واجهات البرمجيات التطبيقية (APIs) للبرامج بالتحدث مع بعضها البعض. يعد REST النمط الأكثر شيوعًا (HTTP + JSON)، لكن GraphQL (لغة استعلام للبيانات)، و WebSockets (للوقت الفعلي)، و gRPC (RPC سريع) تخدم احتياجات مختلفة. تستخدم المصادقة الرموز (Bearer، مفاتيح API) أو OAuth لتفويض المستخدم. تعيد الأخطاء رموز الحالة (2xx للنجاح، 4xx لخطأ العميل، 5xx لخطأ الخادم). أتقن هذه الأنماط وستتمكن من استهلاك أي API بثقة.
الـ API هو بمثابة عقد: "اتصل بي ببيانات X، وسأعطيك نتيجة Y". بدون الـ APIs، سيكون كل شيء معزولاً. بفضلها، يتحدث تطبيقك مع معالجي الدفع، وخدمات الخرائط، ونماذج الذكاء الاصطناعي، وقواعد البيانات. يغطي هذا الدليل النموذج الذهني (ما يحدث بالفعل)، والأنماط الأكثر شيوعًا (REST، GraphQL، WebSocket)، وأمثلة عملية يمكنك تشغيلها اليوم. سواء كنت تدمج خدمة طرف ثالث أو تبني API ليستخدمه الآخرون، فإن فهم هذه الأنماط يجعلك مبرمجًا متمكنًا.
النموذج الذهني: ما هو الـ API؟
ببساطة: الـ API هو دالة (function) موجودة على خادم شخص آخر تقوم باستدعائها عبر الإنترنت.
// Local function
function getUser(userId) {
return database.query(`SELECT * FROM users WHERE id = ${userId`);
}
// API (same thing, but over HTTP)
fetch('https://API.example.com/users/123')
.then(res => res.json());
الفرق الجوهري: في الدوال المحلية، تستدعيها مباشرة. أما مع الـ APIs، فأنت ترسل طلبًا (request) عبر HTTP، ويرسل الخادم ردًا (response).
كل طلب API يحتوي على:
- الطريقة (Method) (أي إجراء: GET، POST، PUT، DELETE)
- نقطة النهاية (Endpoint) (أين: /users/123)
- الترويسات (Headers) (بيانات وصفية: المصادقة، نوع المحتوى)
- الجسم (Body) (حمولة بيانات اختيارية)
كل رد API يحتوي على:
- رمز الحالة (Status code) (نجاح أو فشل: 200، 404، 500)
- الترويسات (Headers) (بيانات وصفية حول الرد)
- الجسم (Body) (البيانات الفعلية، عادةً بتنسيق JSON)
REST: النمط الأكثر شيوعًا
REST (Representational State Transfer) هو المعيار الصناعي. يستخدم أفعال HTTP لوصف الإجراءات على الموارد (الأسماء).
أساسيات REST
GET /posts → Fetch all posts
GET /posts/123 → Fetch post #123
POST /posts → Create a new post
PUT /posts/123 → Update post #123
DELETE /posts/123 → Delete post #123
لماذا تهم الأفعال والأسماء:
- GET آمن (لا يغير البيانات)
- DELETE خطير (يزيل البيانات)
- POST ينشئ؛ PUT يحدث
مثال REST: جلب البيانات
// Simple GET request
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(res => res.json())
.then(data => console.log(data));
// Output: { id: 1, title: "...", body: "...", userId: 1 }
مثال REST: إنشاء بيانات (POST)
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' ,
body: JSON.stringify({
title: 'My Post',
body: 'This is the content',
userId: 1
)
)
.then(res => res.json())
.then(data => console.log(data));
// Output: { id: 101, title: "My Post", body: "This is the content", userId: 1 }
مثال REST: تحديث البيانات (PUT)
fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' ,
body: JSON.stringify({
id: 1,
title: 'Updated Title',
body: 'Updated body',
userId: 1
)
)
.then(res => res.json())
.then(data => console.log(data));
مثال REST: حذف البيانات
fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'DELETE'
)
.then(res => res.json())
.then(data => console.log('Deleted:', data));
GraphQL: لغة استعلام للـ APIs
تسمح لك GraphQL بطلب البيانات التي تحتاجها بالضبط — لا أكثر ولا أقل.
REST مقابل GraphQL
REST:
GET /posts/1
→ { id, title, body, userId, createdAt, updatedAt, authorEmail, ... }
(تحصل على كل شيء؛ إهدار للبيانات)
GraphQL:
query {
post(id: 1) {
title
body
author { name email → { post: { title: "...", body: "...", author: { name: "...", email: "..." (تحصل فقط على ما طلبته)
مثال GraphQL
const query = `
query {
posts {
id
title
author {
name
}
}
}
`;
fetch('https://API.example.com/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' ,
body: JSON.stringify({ query )
)
.then(res => res.json())
.then(data => console.log(data.data.posts));
المزايا:
- لا يوجد جلب زائد (تحصل فقط على ما تحتاجه)
- لا يوجد جلب ناقص (لا داعي لرحلات ذهاب وإياب متعددة)
- كتابة قوية (المخطط يصف ما هو متاح)
العيوب:
- أكثر تعقيدًا في التعلم
- رفع الملفات قد يكون صعبًا
- تعقيد الاستعلام يمكن أن يثقل كاهل الخوادم
WebSocket: الاتصال في الوقت الفعلي
يحافظ WebSocket على اتصال مفتوح للتحديثات في الوقت الفعلي (الدردشة، الإشعارات، البيانات المباشرة).
مثال WebSocket
const ws = new WebSocket('wss://API.example.com/live');
ws.addEventListener('open', () => {
console.log('Connected');
ws.send(JSON.stringify({ action: 'subscribe', channel: 'prices' ));
);
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Price update:', data);
);
ws.addEventListener('close', () => {
console.log('Disconnected');
);
حالات الاستخدام:
- الدردشة في الوقت الفعلي
- أسعار الأسهم المباشرة، العملات المشفرة
- الإشعارات المباشرة
- الأدوات التعاونية (مثل Google Docs)
الفرق عن REST:
- REST هو طلب-رد (العميل يسأل، الخادم يجيب، ينتهي الاتصال)
- WebSocket هو ثنائي الاتجاه (العميل والخادم يرسلان البيانات في أي وقت)
المصادقة: كيف تعرف الـ APIs من أنت
1. مفتاح API
رمز بسيط يتم إرساله مع كل طلب.
fetch('https://API.example.com/data', {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' )
المميزات: بسيط، يعمل للاتصال بين الخوادم العيوب: إذا تسرب، يمكن لأي شخص استخدامه
2. OAuth 2.0 (تفويض المستخدم)
يقوم المستخدم بتسجيل الدخول في تطبيقك، ويمنح الإذن للوصول إلى بياناته في خدمة أخرى (Gmail، GitHub، Spotify). تطبيقك لا يرى كلمة المرور الخاصة بهم أبدًا.
// User clicks "Sign in with Google"
// Google authenticates user, sends your app a token
// Your app uses that token to fetch user's Google data
fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
headers: { 'Authorization': `Bearer ${googleToken` )
المميزات: يتحكم المستخدم في البيانات التي تصل إليها؛ أنت لا تتعامل مع كلمات المرور أبدًا العيوب: إعداد أكثر تعقيدًا
3. ملفات تعريف الارتباط للجلسة (Session Cookies)
يقوم الخادم بتعيين ملف تعريف ارتباط؛ ويرسله المتصفح تلقائيًا مع كل طلب.
// Login endpoint sets a cookie
fetch('https://API.example.com/login', {
method: 'POST',
credentials: 'include', // Send cookies
body: JSON.stringify({ username)
)
// Subsequent requests automatically include the cookie
fetch('https://API.example.com/me', {
credentials: 'include'
)
المميزات: يعمل بشكل جيد لتطبيقات الويب؛ يتم إرسال ملف تعريف الارتباط تلقائيًا العيوب: هجمات CSRF ممكنة؛ أقل ملاءمة لعملاء الهاتف المحمول/الـ API
رموز حالة HTTP: فهم الردود
| الرمز | المعنى | مثال |
|---|---|---|
| 2xx | نجاح | |
| 200 | OK (نجح الطلب) | GET /posts ← يعيد المنشورات |
| 201 | Created (تم إنشاء مورد جديد) | POST /posts ← ينشئ منشورًا |
| 204 | No Content (نجاح، لم يتم إرجاع بيانات) | DELETE /posts/1 |
| 3xx | إعادة توجيه | |
| 301 | Moved Permanently | رابط قديم ← رابط جديد |
| 304 | Not Modified (الرد المخزن مؤقتًا سليم) | ترويسة If-Modified-Since |
| 4xx | خطأ عميل | |
| 400 | Bad Request (طلب غير صحيح) | حقل مطلوب مفقود |
| 401 | Unauthorized (المصادقة مطلوبة) | نسيت مفتاح الـ API |
| 403 | Forbidden (ليس لديك إذن) | غير المسؤول يحاول الوصول لنقطة نهاية المسؤول |
| 404 | Not Found (المورد غير موجود) | GET /posts/999 |
| 429 | Too Many Requests (تجاوز حد الطلبات) | إرسال طلبات كثيرة بسرعة كبيرة |
| 5xx | خطأ خادم | |
| 500 | Internal Server Error (حدث خطأ ما) | خطأ في كود الخادم |
| 503 | Service Unavailable (متوقف مؤقتًا) | صيانة أو ضغط زائد |
القاعدة الذهبية: إذا كانت الحالة 2xx، فقد نجح الطلب. إذا كانت 4xx أو 5xx، فهناك خطأ ما.
التعامل مع الأخطاء: عندما تسوء الأمور
async function fetchData(url) {
try {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP ${res.status: ${res.statusText`);
return await res.json();
catch (err) {
console.error('API error:'.message);
// Handle gracefully: show user message, retry, etc.
تحديد معدل الطلبات: كن مهذبًا
غالبًا ما تضع الـ APIs حدودًا للطلبات لمنع إساءة الاستخدام.
// Check headers for rate limit info
const remaining = res.headers.get('X-RateLimit-Remaining');
const resetTime = res.headers.get('X-RateLimit-Reset');
if (remaining === '0') {
console.log(`Rate limited. Reset at ${new Date(resetTime * 1000)`);
مثال واقعي: بناء أداة للبحث عن مستخدمي GitHubasync function getGitHubUser(username) {
const url = `https://API.GitHub.com/users/${username}`;
try {
const res = await fetch(url);
if (res.status === 404) {
throw new Error('User not found');
}
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const user = await res.json();
console.log(`${user.name} has ${user.public_repos} repos`);
} catch (err) {
console.error('Error:', err.message);
}
}
getGitHubUser('torvalds'); // Linus Torvalds
الخلاصة
تعد الـ APIs هي الطريقة التي تتواصل بها البرمجيات الحديثة. يهيمن REST بسبب بساطته؛ ويتفوق GraphQL في المرونة؛ بينما يتيح WebSocket التواصل في الوقت الفعلي (real-time). تختلف طرق المصادقة (Authentication) حسب حالة الاستخدام (مفاتيح API، أو OAuth، أو ملفات تعريف الارتباط cookies). تخبرك رموز الحالة (Status codes) بالنجاح أو الفشل؛ ومعالجة الأخطاء تجعل تطبيقك مرنًا. بإتقان هذه الأنماط، يمكنك دمج أي خدمة خارجية، وبناء APIs يستهلكها الآخرون، وتصحيح مشكلات الشبكة بثقة. ابدأ بـ REST API بسيط (مثل JSONPlaceholder)، ثم انتقل إلى الخدمات الحقيقية (GitHub، Stripe، OpenAI) عندما تشعر بالارتياح.