Skip to content

معالجة الأخطاء

تنسيق استجابة الخطأ

تتبع جميع أخطاء API بنية JSON متسقة مع رمز حالة HTTP مناسب:

json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong"
  }
}

حقل code هو معرّف ثابت قابل للقراءة آلياً يمكنك استخدامه في منطق معالجة الأخطاء. حقل message يوفر سياقاً إضافياً وقد يختلف بين حالات نفس رمز الخطأ.

فئات الأخطاء

أخطاء المصادقة (401)

تُرجع عندما لا يمكن مصادقة الطلب.

الرمزالوصف
UNAUTHORIZEDترويسة Authorization مفقودة أو مشوّهة أو تحتوي على رمز غير صالح.
KEY_EXPIREDكان مفتاح API صالحاً لكنه تجاوز تاريخ انتهاء صلاحيته. أنشئ مفتاحاً جديداً للمتابعة.
json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid Authorization header"
  }
}

أخطاء التفويض (403)

تُرجع عندما لا يملك المستخدم المصادق عليه صلاحية الوصول إلى المورد المطلوب.

الرمزالوصف
FORBIDDENتحاول الوصول إلى أو تعديل مورد ينتمي إلى مستخدم آخر (مثال: إلغاء مفتاح API لشخص آخر).

أخطاء عدم العثور (404)

تُرجع عندما لا يوجد المورد المطلوب.

الرمزالوصف
NOT_FOUNDالمورد المحدد في عنوان URL (استخراج أو مفتاح API، إلخ) غير موجود أو تم حذفه.

أخطاء التحقق (400)

تُرجع عندما يكون جسم الطلب أو المعاملات غير صالحة.

الرمزالوصف
VALIDATION_ERRORفشل جسم الطلب في التحقق من المخطط. حقل message يصف أي الحقول غير صالحة.
MAX_KEYS_REACHEDلقد وصلت إلى الحد الأقصى وهو 10 مفاتيح API نشطة. ألغِ مفتاحاً موجوداً قبل إنشاء مفتاح جديد.
json
{
  "error": {
    "code": "MAX_KEYS_REACHED",
    "message": "Maximum of 10 active API keys allowed"
  }
}

أخطاء تحديد المعدل (429)

تُرجع عند تجاوز حدود الاستخدام.

الرمزالوصف
USAGE_LIMIT_EXCEEDEDتم الوصول إلى حد الاستخراج الشهري. قم بترقية خطتك أو انتظر حتى فترة الفوترة التالية.
json
{
  "error": {
    "code": "USAGE_LIMIT_EXCEEDED",
    "message": "Monthly extraction limit reached (25/25). Upgrade your plan for more extractions."
  }
}

أخطاء الخادم (500)

تُرجع عند حدوث شيء غير متوقع على جانب الخادم.

الرمزالوصف
INTERNAL_ERRORحدث خطأ غير متوقع في الخادم. يتم تسجيل هذه الأخطاء والتحقيق فيها تلقائياً.
EXTRACTION_FAILEDواجه خط أنابيب معالجة الذكاء الاصطناعي خطأً أثناء استخراج البيانات من مستندك. قد يكون المستند تالفاً أو غير قابل للقراءة أو بتنسيق غير مدعوم.

الأخطاء القابلة لإعادة المحاولة

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

الرمزقابل لإعادة المحاولةالإجراء
INTERNAL_ERRORنعمأعد المحاولة مع تراجع أسي
EXTRACTION_FAILEDنعمأعد المحاولة -- قد ينتج الذكاء الاصطناعي نتيجة مختلفة. إذا استمر، تحقق من جودة المستند
USAGE_LIMIT_EXCEEDEDلاقم بترقية خطتك أو انتظر حتى فترة الفوترة التالية
UNAUTHORIZEDلاأصلح بيانات اعتماد المصادقة
KEY_EXPIREDلاأنشئ مفتاح API جديداً
FORBIDDENلاتحاول الوصول إلى مورد لا تملكه
NOT_FOUNDلاالمورد غير موجود -- تحقق من المعرّف
VALIDATION_ERRORلاأصلح جسم الطلب ليطابق المخطط المتوقع
MAX_KEYS_REACHEDلاألغِ مفتاحاً موجوداً قبل إنشاء مفتاح جديد

استراتيجية إعادة المحاولة

للأخطاء القابلة لإعادة المحاولة، استخدم التراجع الأسي لتجنب إرهاق الخادم. إليك تنفيذاً قابلاً لإعادة الاستخدام:

typescript
interface ApiResponse<T> {
  data?: T;
  error?: { code: string; message: string };
}

async function fetchWithRetry<T>(
  url: string,
  options: RequestInit,
  maxRetries = 3,
): Promise<ApiResponse<T>> {
  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const body = await response.json();

      if (response.ok) {
        return body as ApiResponse<T>;
      }

      const errorCode = body?.error?.code;

      // Only retry server errors
      if (
        (errorCode === "INTERNAL_ERROR" || errorCode === "EXTRACTION_FAILED") &&
        attempt < maxRetries
      ) {
        const delayMs = 1000 * Math.pow(2, attempt); // 1s, 2s, 4s
        console.log(`Retrying in ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})...`);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }

      // Non-retryable error -- return immediately
      return body as ApiResponse<T>;
    } catch (err) {
      lastError = err as Error;

      if (attempt < maxRetries) {
        const delayMs = 1000 * Math.pow(2, attempt);
        await new Promise((resolve) => setTimeout(resolve, delayMs));
        continue;
      }
    }
  }

  throw lastError ?? new Error("Max retries exceeded");
}

الاستخدام:

typescript
const result = await fetchWithRetry<ExtractionResult>(
  "https://api.docmap.io/v1/extractions/run",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      templateId: "tmpl_abc123",
      fileName: "invoice.pdf",
      pdfBase64: encodedPdf,
      mimeType: "application/pdf",
    }),
  },
);

if (result.error) {
  console.error(`Extraction failed: [${result.error.code}] ${result.error.message}`);
} else {
  console.log("Extracted data:", result.data);
}

أفضل الممارسات

  • تحقق دائماً من رمز حالة HTTP أولاً. حالة 2xx تعني النجاح؛ أي شيء آخر هو خطأ. لا تفترض أن جسم الاستجابة يحتوي على حقل data دون التحقق.

  • حلّل جسم الخطأ للحصول على حقل code. استخدم code (وليس message) في تدفق التحكم الخاص بك. قد تتغير رسائل الخطأ بمرور الوقت، لكن رموز الأخطاء ثابتة.

  • عالج رموز خطأ محددة. فرّع على الرموز المعروفة مثل USAGE_LIMIT_EXCEEDED أو KEY_EXPIRED لعرض رسائل مستهدفة لمستخدميك أو تشغيل سير عمل محدد.

  • سجّل الأخطاء غير المعروفة. إذا واجهت رمز خطأ لا تعالجه بشكل صريح، سجّل الاستجابة الكاملة (رمز الحالة ورمز الخطأ والرسالة) لتصحيح الأخطاء.

  • لا تعد محاولة أخطاء 4xx. أخطاء المصادقة والتفويض والتحقق وعدم العثور لن تُحل من تلقاء نفسها. أصلح المشكلة الأساسية قبل إعادة المحاولة.

  • حدد حداً لإعادة المحاولة. لا تعد المحاولة إلى ما لا نهاية. ثلاث محاولات مع تراجع أسي (1 ثانية، 2 ثانية، 4 ثوانٍ) هي الافتراضي المعقول لأخطاء الخادم.

وثائق DocMap API