التعامل مع استجابات API وأخطائها
تحليل استجابات JSON، ورموز الأخطاء، وأنماط معالجة الاستثناءات
التعامل مع استجابات API وأخطائها درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.
كائن الاستجابة
يعيد كل استدعاء لـ requests كائن استجابة. ويحتوي هذا الكائن على كل ما أعاده الخادم: رمز الحالة والرؤوس والمتن. افحص رمز الحالة دائمًا قبل معالجة المتن، إذ إن الاستجابة التي تحمل الحالة 500 لا تزال تحتوي على متن، لكنه لن يتضمن البيانات التي طلبتها.
import requests
response = requests.get('https://api.example.com/data')
# Key attributes of the response
print(response.status_code) # e.g. 200
print(response.headers) # dict of response headers
print(response.headers.get('Content-Type')) # 'application/json'
print(response.text) # raw response body as string
print(response.content) # raw bytesتحليل JSON باستخدام response.json()
استدعِ response.json() لتحليل متن الاستجابة تلقائيًا باعتباره JSON وتحويله إلى قاموس أو قائمة في Python. وهذا يعادل json.loads(response.text)، لكنه يتحقق أيضًا من ملاءمة Content-Type.
لا تستدعِ .json() إلا عندما تعلم أن الاستجابة هي JSON فعلًا، فتحقق أولًا من رأس Content-Type.
import requests
response = requests.get(
'https://api.example.com/users/42',
headers={'Authorization': 'Bearer YOUR_KEY'}
)
# Parse JSON body
user = response.json()
# Access fields safely with .get()
name = user.get('name', 'Unknown')
email = user.get('email', '')
roles = user.get('roles', [])
print(f'User: {name} ({email})')
print(f'Roles: {roles}')التحقق من status_code قبل التحليل
لا تستدعِ response.json() مطلقًا قبل التأكد من نجاح الطلب. فكثيرًا ما تعيد استجابات الأخطاء (4xx/5xx) تفاصيل أخطاء بتنسيق JSON، وهي مفيدة لتصحيح الأخطاء، لكنها ليست البيانات التي تحتاج إليها. تحقّق دائمًا من status_code أولًا.
import requests
response = requests.post(
'https://api.example.com/tasks',
json={'title': 'Write report'},
headers={'Authorization': 'Bearer YOUR_KEY'}
)
if response.status_code == 201:
task = response.json()
print('Task created, ID:', task['id'])
elif response.status_code == 400:
error = response.json()
print('Validation error:', error.get('message'))
elif response.status_code == 401:
print('Auth failed — check your token')
else:
print(f'Unexpected status {response.status_code}: {response.text[:200]}')raise_for_status() — رفع الأخطاء تلقائيًا
ترفع response.raise_for_status() استثناء HTTPError تلقائيًا إذا كان رمز الحالة 4xx أو 5xx. وتُعد هذه طريقة واضحة لتحويل استجابات HTTP غير الصالحة إلى استثناءات في Python، مما يتيح لك استخدام try/except بدلًا من سلاسل if/elif الطويلة.
import requests
from requests.exceptions import HTTPError
try:
response = requests.get(
'https://api.example.com/users/9999',
headers={'Authorization': 'Bearer YOUR_KEY'}
)
response.raise_for_status() # raises if status >= 400
user = response.json()
print('Found user:', user['name'])
except HTTPError as e:
print(f'HTTP error: {e.response.status_code}')
print('Details:', e.response.text[:300])التعامل مع JSONDecodeError
تعيد بعض واجهات API أحيانًا استجابة غير بتنسيق JSON رغم توقعك لذلك، مثل صفحة خطأ HTML من الخادم أو متن فارغ أو ملف ثنائي. ويؤدي استدعاء response.json() في هذه الحالات إلى رفع json.JSONDecodeError. احرص دائمًا على التقاط هذا الاستثناء لتجنب تعطل الوكيل دون تنبيه.
import requests
import json
response = requests.get(
'https://api.example.com/report',
headers={'Authorization': 'Bearer YOUR_KEY'}
)
try:
data = response.json()
except json.JSONDecodeError as e:
print(f'Response is not valid JSON: {e}')
print('Content-Type:', response.headers.get('Content-Type'))
print('First 200 chars:', response.text[:200])
# Decide: is this an HTML error page? A CSV file?
data = None
if data is None:
print('Falling back to text processing')ConnectionError — مشكلات الشبكة
يحدث ConnectionError عندما يتعذر على وكيلك الوصول إلى الخادم إطلاقًا، مثل فشل تحليل DNS أو توقف الخادم عن العمل أو حجب جدار الحماية للطلب. وهذا فشل على مستوى الشبكة يحدث قبل بدء أي اتصال HTTP.
وبخلاف حالة 5xx، لا تمثل هذه المشكلة استجابة من الخادم، إذ لم يحدث الاتصال أصلًا.
import requests
from requests.exceptions import ConnectionError
try:
response = requests.get('https://api.example.com/data')
data = response.json()
except ConnectionError as e:
print('Cannot reach server. Possible causes:')
print('- DNS failure (bad hostname)')
print('- Server is down')
print('- No internet connection')
print('- Firewall blocking the port')
print(f'Error detail: {e}')
# Consider: queue the request for retry when connectivity returnsTimeout — منع الوكلاء من التعطل
ينتظر requests افتراضيًا الاستجابة إلى ما لا نهاية. وقد يؤدي خادم بطيء أو متوقف عن الاستجابة إلى تجميد وكيلك بلا نهاية. عيّن دائمًا مهلة زمنية، وهي مجموعة من (connect_timeout, read_timeout) بالثواني. ويُرفع استثناء Timeout إذا لم يستجب الخادم في الوقت المحدد.
import requests
from requests.exceptions import Timeout
try:
response = requests.get(
'https://api.example.com/slow-endpoint',
headers={'Authorization': 'Bearer YOUR_KEY'},
timeout=(5, 30) # 5s to connect, 30s to read
)
data = response.json()
except Timeout:
print('Request timed out after 30 seconds')
print('Options: retry, use cached result, or alert operator')معالجة شاملة للاستثناءات
في الوكلاء المخصصة لبيئة الإنتاج، التقط جميع استثناءات requests ضمن تسلسل هرمي متسق. فـ requests.exceptions.RequestException هو الفئة الأساسية لجميع أخطاء requests، والتقاطه يمنحك شبكة أمان لمشكلات الشبكة غير المتوقعة.
import requests
import json
from requests.exceptions import (
ConnectionError, Timeout, HTTPError, RequestException
)
def safe_api_call(url, headers):
try:
r = requests.get(url, headers=headers, timeout=(5, 30))
r.raise_for_status()
return r.json()
except Timeout:
print('ERROR: Request timed out')
except ConnectionError:
print('ERROR: Cannot reach server')
except HTTPError as e:
print(f'ERROR: HTTP {e.response.status_code}')
try:
print('API error:', e.response.json().get('message'))
except json.JSONDecodeError:
print('Non-JSON error body')
except RequestException as e:
print(f'ERROR: Unexpected request error: {e}')
return Noneتسجيل الاستجابات لتصحيح الأخطاء
عندما يتصرف وكيل بطريقة غير صحيحة، تحتاج إلى سياق كافٍ لتشخيص المشكلة. سجّل طريقة الطلب وعنوان URL ورمز الحالة وتفاصيل الاستجابة ذات الصلة، لكن لا تسجّل مفاتيح API مطلقًا. استخدم وحدة logging المضمنة في Python بدلًا من عبارات الطباعة في وكلاء الإنتاج.
import logging
import requests
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('agent.api')
def logged_request(method, url, **kwargs):
logger.info(f'-> {method.upper()} {url}')
response = requests.request(method, url, **kwargs)
logger.info(
f'<- {response.status_code} '
f'({len(response.content)} bytes) '
f'{response.elapsed.total_seconds():.2f}s'
)
if response.status_code >= 400:
logger.error(f'Error body: {response.text[:500]}')
return responseالتعامل مع الاستجابات المقسمة إلى صفحات
تعيد العديد من واجهات API البيانات على صفحات. ويجب على وكيلك اتباع روابط الترقيم للحصول على جميع النتائج. ابحث عن عنوان URL التالي next في الاستجابة أو عن حقل page/cursor، وكرّر العملية حتى لا تبقى صفحات أخرى.
import requests
def get_all_items(base_url, headers):
all_items = []
url = f'{base_url}/items?page=1&limit=100'
while url:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
all_items.extend(data.get('items', []))
# Follow 'next' link if present
url = data.get('next_page_url') # None stops the loop
print(f'Fetched {len(all_items)} items so far...')
print(f'Total: {len(all_items)} items')
return all_itemsبث الاستجابات الكبيرة
بالنسبة إلى الاستجابات الكبيرة، مثل الملفات أو مخرجات الذكاء الاصطناعي الطويلة، استخدم stream=True لتجنب تحميل الاستجابة بأكملها في الذاكرة دفعة واحدة. اقرأ الاستجابة على شكل أجزاء. وهذا أمر ضروري عندما يعالج وكيلك مجموعات بيانات كبيرة أو يبث نصًا من إنشاء الذكاء الاصطناعي.
import requests
response = requests.get(
'https://api.example.com/large-report',
headers={'Authorization': 'Bearer YOUR_KEY'},
stream=True
)
response.raise_for_status()
# Write streamed content to file
with open('report.json', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print('Download complete')
# For streaming JSON lines (NDJSON):
for line in response.iter_lines():
if line:
import json
record = json.loads(line)
print(record)اختبار سريع: raise_for_status
اختبر مدى فهمك لمعالجة أخطاء الاستجابات.
مراجعة معالجة الاستجابات
إن معالجة الاستجابات بطريقة متينة هي ما يميز الوكيل الهش عن الوكيل الموثوق:
- تحقّق دائمًا من
status_codeقبل تحليل المتن - استخدم
response.json()للتحليل، والتقطJSONDecodeErrorإذا كان المتن قد لا يكون بتنسيق JSON - استخدم
raise_for_status()لتحويل أخطاء HTTP إلى استثناءات - التقط
ConnectionErrorلفشل الشبكة وTimeoutللخوادم البطيئة - عيّن دائمًا مجموعة
timeout=(connect, read)في كل طلب - سجّل الطلبات والاستجابات، من دون المفاتيح، لتسهيل تصحيح الأخطاء
الأسئلة الشائعة
هل درس «التعامل مع استجابات API وأخطائها» مجاني؟
نعم — نص درس «التعامل مع استجابات API وأخطائها» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.
ماذا ستتعلم في «التعامل مع استجابات API وأخطائها»؟
تحليل استجابات JSON، ورموز الأخطاء، وأنماط معالجة الاستثناءات تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟
لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «التعامل مع استجابات API وأخطائها»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟
نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات REST API لمطوري الوكلاء
- المصادقة: مفاتيح API وOAuth
- التعامل مع استجابات API وأخطائها
- تحديد معدل الطلبات ومنطق إعادة المحاولة