إرسال الطلبات (GET & POST) ومعالجة استجابات الـ API بفعالية


إرسال الطلبات (GET & POST) ومعالجة استجابات الـ API بفعالية

إرسال الطلبات (GET & POST) ومعالجة استجابات الـ API بفعالية

ماذا سنتعلم اليوم؟ في هذا الدرس، سنتعلم كيفية التفاعل مع واجهات برمجة التطبيقات (APIs) باستخدام لغة بايثون. سنقوم بإرسال طلبات GET لاسترداد البيانات وطلبات POST لإرسالها، مع التركيز على معالجة الاستجابات بكفاءة والتعامل مع الأخطاء.

الخطوة 1: إعداد البيئة وإرسال طلب GET بسيط

للبدء، نحتاج إلى تثبيت مكتبة requests، وهي المكتبة الأكثر شيوعاً لإجراء طلبات HTTP في بايثون. بعد التثبيت، سنقوم بإرسال أول طلب GET لاسترداد بيانات من API عام.

ملاحظة تقنية: طلب GET يُستخدم لاسترداد البيانات من خادم. يجب أن يكون آمناً (لا يغير حالة الخادم) وقابلاً للتكرار (تكرار الطلب لا يؤدي إلى آثار جانبية مختلفة).

لتثبيت المكتبة، استخدم الأمر التالي في سطر الأوامر:

pip install requests

الآن، لنقم بإنشاء سكربت بايثون لإرسال طلب GET:

import requests # استيراد مكتبة requests للتعامل مع طلبات HTTP

# تحديد عنوان URL لواجهة برمجة تطبيقات عامة (JSONPlaceholder provides fake API data)
api_url = "https://jsonplaceholder.typicode.com/todos/1"

try:
    # إرسال طلب GET إلى عنوان URL المحدد
    response = requests.get(api_url)

    # التحقق مما إذا كانت الاستجابة ناجحة (رمز الحالة 200 OK)
    if response.status_code == 200:
        # طباعة نص الاستجابة الأولية
        print("استجابة ناجحة (GET):")
        print(response.text)

        # تحويل الاستجابة إلى كائن JSON (إذا كان المحتوى JSON)
        data = response.json()
        print("\nالبيانات بعد التحويل إلى JSON:")
        print(f"العنوان: {data['title']}")
        print(f"مكتمل: {data['completed']}")
    else:
        # طباعة رسالة خطأ إذا لم تكن الاستجابة 200
        print(f"فشل طلب GET. رمز الحالة: {response.status_code}")

except requests.exceptions.RequestException as e:
    # التعامل مع أي أخطاء تتعلق بالشبكة أو الطلب نفسه
    print(f"حدث خطأ أثناء الاتصال بالـ API: {e}")

الخطوة 2: معالجة استجابات الـ API والتعامل مع الأخطاء بفعالية

من الضروري التعامل مع الاستجابات بشكل صحيح، بما في ذلك التحقق من رمز الحالة واستخراج البيانات، بالإضافة إلى معالجة الأخطاء المحتملة مثل مشاكل الشبكة أو الأذونات. سنستخدم response.raise_for_status() لرفع استثناء تلقائياً إذا كان رمز الحالة يشير إلى خطأ.

ملاحظة تقنية: response.raise_for_status() طريقة مفيدة لتبسيط معالجة الأخطاء. ستقوم برفع استثناء HTTPError إذا كان رمز حالة الاستجابة بين 400 و 500 (مثل 404 Not Found أو 500 Internal Server Error).

إليك كيفية تحسين معالجة الاستجابات والأخطاء:

import requests

api_url_todos = "https://jsonplaceholder.typicode.com/todos" # عنوان URL لاسترداد قائمة المهام

try:
    # إرسال طلب GET لاسترداد جميع المهام
    response_all_todos = requests.get(api_url_todos)
    response_all_todos.raise_for_status() # رفع استثناء لرموز حالة HTTP الخاطئة (4xx أو 5xx)

    # تحويل الاستجابة إلى قائمة من كائنات JSON
    todos = response_all_todos.json()

    print("\nأول 3 مهام من قائمة الـ API:")
    # طباعة عنوان أول 3 مهام
    for i, todo in enumerate(todos[:3]): # تكرار عبر أول 3 عناصر فقط
        print(f"  - [ID: {todo['id']}] {todo['title']} (مكتمل: {todo['completed']})")

    # محاولة طلب إلى عنوان URL غير موجود لإظهار معالجة الأخطاء
    invalid_url = "https://jsonplaceholder.typicode.com/nonexistent-path"
    print(f"\nمحاولة طلب إلى URL غير موجود: {invalid_url}")
    error_response = requests.get(invalid_url)
    error_response.raise_for_status() # هذا السطر سيرفع استثناء HTTPError

except requests.exceptions.HTTPError as http_err:
    # التعامل مع أخطاء HTTP (مثل 404 Not Found، 500 Internal Server Error)
    print(f"خطأ HTTP حدث: {http_err} (لـ URL: {http_err.response.url})")
except requests.exceptions.ConnectionError as conn_err:
    # التعامل مع أخطاء الاتصال (مثل عدم وجود اتصال بالإنترنت)
    print(f"خطأ في الاتصال: {conn_err}")
except requests.exceptions.Timeout as timeout_err:
    # التعامل مع أخطاء انتهاء المهلة
    print(f"انتهت مهلة الطلب: {timeout_err}")
except requests.exceptions.RequestException as req_err:
    # التعامل مع أي أخطاء أخرى غير مصنفة من مكتبة requests
    print(f"حدث خطأ غير متوقع في الطلب: {req_err}")
except ValueError:
    # التعامل مع الخطأ إذا لم يكن محتوى الاستجابة بصيغة JSON صالحة
    print("فشل تحليل JSON من الاستجابة.")

الخطوة 3: إرسال طلب POST لإضافة بيانات

طلب POST يُستخدم لإرسال البيانات إلى الخادم، غالباً لإنشاء مورد جديد. على سبيل المثال، إضافة منشور جديد أو مستخدم جديد. سنرسل بيانات بصيغة JSON في جسم الطلب.

ملاحظة تقنية: طلب POST ليس آمناً (يغير حالة الخادم) وغير قابل للتكرار (تكرار الطلب قد يؤدي إلى إنشاء موارد متعددة). البيانات عادة ما تُرسل في جسم الطلب، وغالباً ما تكون بصيغة JSON أو بيانات نموذج.

هذا مثال على كيفية إرسال طلب POST لإنشاء منشور جديد:

import requests

post_api_url = "https://jsonplaceholder.typicode.com/posts" # عنوان URL لإرسال منشورات جديدة

# البيانات التي سنرسلها في طلب POST
new_post_data = {
    "title": "عنوان المنشور الجديد بواسطة بايثون",
    "body": "هذا هو نص المنشور الذي تم إنشاؤه باستخدام طلب POST من سكربت بايثون.",
    "userId": 1 # معرف المستخدم الذي أنشأ المنشور
}

try:
    # إرسال طلب POST. نستخدم المعامل 'json' لإرسال البيانات كـ JSON تلقائياً
    post_response = requests.post(post_api_url, json=new_post_data)
    post_response.raise_for_status() # التحقق من نجاح الطلب

    # طباعة رمز الحالة والاستجابة من الخادم
    print(f"\nاستجابة طلب POST (رمز الحالة: {post_response.status_code}):")
    created_post = post_response.json()
    print(f"المنشور الذي تم إنشاؤه: {created_post}")
    print(f"معرف المنشور الجديد: {created_post['id']}") # الخادم عادةً ما يُرجع معرفاً فريداً للمورد الجديد

except requests.exceptions.RequestException as e:
    print(f"حدث خطأ أثناء إرسال طلب POST: {e}")

الكود النهائي الكامل

إليك السكربت كاملاً الذي يجمع جميع الخطوات التي تعلمناها:

import requests # استيراد مكتبة requests للتعامل مع طلبات HTTP

# ----------------------------------------------------------------------
# الخطوة 1 & 2: إرسال طلب GET ومعالجة الاستجابات والأخطاء
# ----------------------------------------------------------------------
print("--- بدء اختبار طلبات GET ---")

api_url_single_todo = "https://jsonplaceholder.typicode.com/todos/1" # عنوان URL لمهام فردية
api_url_all_todos = "https://jsonplaceholder.typicode.com/todos"     # عنوان URL لجميع المهام
invalid_url_example = "https://jsonplaceholder.typicode.com/nonexistent-path"

try:
    # طلب GET لمهام فردية
    print(f"\nإرسال طلب GET إلى: {api_url_single_todo}")
    response_single = requests.get(api_url_single_todo)
    response_single.raise_for_status() # رفع استثناء لرموز حالة HTTP الخاطئة
    todo_item = response_single.json()
    print(f"  - تم استرداد المهمة (ID: {todo_item['id']}): {todo_item['title']} (مكتمل: {todo_item['completed']})")

    # طلب GET لجميع المهام (أول 3 فقط للتبسيط)
    print(f"\nإرسال طلب GET إلى: {api_url_all_todos} (أول 3 نتائج)")
    response_all = requests.get(api_url_all_todos)
    response_all.raise_for_status()
    all_todos = response_all.json()
    print("  - أول 3 مهام:")
    for i, todo in enumerate(all_todos[:3]):
        print(f"    - [ID: {todo['id']}] {todo['title']} (مكتمل: {todo['completed']})")

    # مثال على معالجة خطأ (URL غير موجود)
    print(f"\nمحاولة طلب GET إلى URL غير موجود: {invalid_url_example}")
    error_test_response = requests.get(invalid_url_example)
    error_test_response.raise_for_status() # هذا سيلقي HTTPError

except requests.exceptions.HTTPError as http_err:
    print(f"  - خطأ HTTP حدث: {http_err} (رمز الحالة: {http_err.response.status_code})")
except requests.exceptions.ConnectionError as conn_err:
    print(f"  - خطأ في الاتصال بالشبكة: {conn_err}")
except requests.exceptions.Timeout as timeout_err:
    print(f"  - انتهت مهلة الطلب: {timeout_err}")
except requests.exceptions.RequestException as req_err:
    print(f"  - حدث خطأ عام في الطلب: {req_err}")
except ValueError:
    print("  - فشل تحليل JSON من الاستجابة.")

print("--- انتهاء اختبار طلبات GET ---")

# ----------------------------------------------------------------------
# الخطوة 3: إرسال طلب POST لإضافة بيانات
# ----------------------------------------------------------------------
print("\n--- بدء اختبار طلبات POST ---")

post_api_url = "https://jsonplaceholder.typicode.com/posts"

# البيانات التي سيتم إرسالها
new_post_payload = {
    "title": "منشور جديد احترافي من بايثون",
    "body": "محتوى المنشور التجريبي الذي تم إنشاؤه بواسطة سكربت بايثون مع أمثلة فعالة لمعالجة الـ API.",
    "userId": 101 # معرف مستخدم افتراضي
}

try:
    print(f"\nإرسال طلب POST إلى: {post_api_url}")
    # استخدام المعامل json= لإرسال البيانات كـ JSON في جسم الطلب
    post_response = requests.post(post_api_url, json=new_post_payload)
    post_response.raise_for_status() # التحقق من نجاح طلب POST

    created_resource = post_response.json()
    print(f"  - تم إرسال المنشور بنجاح! رمز الحالة: {post_response.status_code}")
    print(f"  - الاستجابة من الخادم (المورد الذي تم إنشاؤه): {created_resource}")
    print(f"  - معرف المورد الجديد: {created_resource.get('id', 'غير متوفر')}")

except requests.exceptions.RequestException as e:
    print(f"  - حدث خطأ أثناء إرسال طلب POST: {e}")

print("--- انتهاء اختبار طلبات POST ---")

النتيجة المتوقعة

عند تشغيل السكربت، ستشاهد الآتي في سطر الأوامر (قد تختلف تفاصيل التواريخ والمعرفات):

  • رسالة تفيد بنجاح طلب GET الأول، مع طباعة تفاصيل مهمة واحدة (ID: 1).
  • قائمة بأول 3 مهام تم استردادها من API Todos.
  • رسالة خطأ HTTP توضح أن URL غير الموجود (nonexistent-path) قد أدى إلى خطأ 404 (Not Found)، مما يبرهن على فعالية معالجة الأخطاء.
  • رسالة تفيد بنجاح طلب POST، مع عرض رمز الحالة 201 (Created) وتفاصيل المنشور الجديد الذي تم إنشاؤه، بما في ذلك المعرف الفريد الذي يُعيده الخادم (عادةً ما يكون أكبر من المعرفات الموجودة، مثل 101).

هذا يوضح كيفية التفاعل بفعالية مع واجهات برمجة التطبيقات باستخدام طلبات GET و POST، والتعامل مع استجاباتها وأخطائها بطريقة احترافية.