> ## Documentation Index
> Fetch the complete documentation index at: https://www.ayrshare.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# أخطاء GraphQL

> كيف تُبلغ Ayrshare GraphQL API عن الأخطاء، بدءًا من رموز حالة HTTP للطلبات غير الصحيحة وصولًا إلى مصفوفة errors والنجاح الجزئي وإعادة المحاولة الآمنة من التكرار وحدود المعدل.

<h2 id="resolver-errors-arrive-with-http-200">
  أخطاء المُحلِّل تصل مع HTTP 200
</h2>

هذا أهم شيء يجب معرفته قبل كتابة شيفرة معالجة الأخطاء.

وفقًا لمواصفة GraphQL over HTTP، يُرجع الطلب الذي يصل إلى المُحلِّلات لدينا **HTTP 200 حتى عندما تفشل عملية ما**. يُبلَغ عن الفشل داخل جسم الاستجابة، وليس عبر رمز الحالة.

لذا فإن هذا التحقق لا يعمل:

```javascript theme={"system"}
// WRONG - will treat a failed request as a success
if (response.ok) {
  return "everything worked";
}
```

تحقّق من الجسم بدلًا من ذلك. بعض أخطاء النقل، مثل 415 عند استخدام `Content-Type` غير مدعوم، يكون جسمها فارغًا، لذا تحقّق من أن الاستجابة بصيغة JSON قبل تحليلها:

```javascript theme={"system"}
if (!response.headers.get("content-type")?.includes("json")) {
  throw new Error(`GraphQL request failed with HTTP ${response.status}`);
}

const result = await response.json();

if (result.errors) {
  for (const error of result.errors) {
    // Errors caught before execution have no extensions, so read it safely.
    console.log(error.message, error.extensions?.status);
  }
}
```

تُكتشف بعض حالات الفشل قبل تنفيذ أي شيء. لا يصل أي منها إلى مُحلِّل ولا يستهلك استدعاء API:

<ul class="custom-bullets">
  <li>يُرجع الطلب غير الصحيح حالة خطأ: <strong>HTTP 400</strong> لـ JSON غير صالح أو غياب <code>query</code>، و<strong>413</strong> لجسم يتجاوز 64 KB، و<strong>405</strong> لطريقة غير <code>POST</code>، و<strong>415</strong> لـ <code>Content-Type</code> غير مدعوم.</li>
  <li>يُرجع الاستعلام غير الصالح وفقًا للمخطط <strong>HTTP 400</strong> فقط إذا أرسل طلبك <code>Accept: application/graphql-response+json</code>. ويشمل ذلك خطأ الصياغة، والحقل غير المعروف، ونوع الوسيط الخاطئ، وقيمة التعداد غير الصالحة، والاستعلام الذي يتجاوز <a href="/docs/apis/graphql/limits#query-limits">حدود الاستعلام</a>. إذا أرسلت <code>Accept: application/json</code>، أو لم ترسل ترويسة <code>Accept</code>، فإن الخطأ نفسه يُرجع <strong>HTTP 200</strong>. وفي كلتا الحالتين، يحتوي الجسم على مصفوفة <code>errors</code> دون <code>data</code>.</li>
</ul>

بمجرد بدء التنفيذ، تُرجع أخطاء التحقق من الإدخال على مستوى المُحلِّل وحالات فشل API، بما في ذلك المصادقة والتفويض وحدود المعدل في الخدمات الأصلية واستجابات 5xx منها، الرمز HTTP 200 مع مصفوفة `errors`.

<h2 id="the-error-shape">
  شكل الخطأ
</h2>

يحمل كل خطأ من أخطاء المُحلِّل حالة API الشبيهة بحالة HTTP في `extensions`:

```json theme={"system"}
{
  "data": { "postHistory": null },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["postHistory"],
      "extensions": {
        "status": 429,
        "retryAfter": 7
      }
    }
  ]
}
```

<ul class="custom-bullets">
  <li><code>message</code>: وصف مقروء للبشر. نُزيل مفاتيح API وبيانات الاعتماد الأخرى من رسائل أخطاء المُحلِّل، لكن الخطأ المتعلق بقيمة أرسلتها، مثل متغير من نوع خاطئ، قد يكرر تلك القيمة. تعامل مع <code>message</code> على أنها قد تكون حساسة قبل تسجيلها.</li>
  <li><code>path</code>: الحقل الذي فشل في استعلامك. عند وجود عدة حقول في طلب واحد، هذه هي الطريقة لمعرفة أيّها فشل.</li>
  <li><code>extensions.status</code>: حالة HTTP التي كان سيُرجعها استدعاء REST المكافئ. اعتمد على هذه القيمة في التفرّع.</li>
  <li><code>extensions.code</code>: رمز خطأ Ayrshare الرقمي، عندما توفّره نقطة النهاية الأساسية.</li>
  <li><code>extensions.retryAfter</code>: يظهر في استجابات 429 الخاصة بالحصة أو حدود المعدل في الخدمات الأصلية عندما يتوفر تأخير لإعادة المحاولة. ولا يظهر في استجابة 429 الخاصة بميزانية الإرسال لكل طلب.</li>
</ul>

استخدم `extensions.code` مع [مرجع رموز الأخطاء](/docs/errors/overview)، أو مرّره إلى `explainError`.

<h2 id="partial-success">
  النجاح الجزئي
</h2>

إذا طلب الطلب عدة أشياء ونجح بعضها فقط، فستحصل على `data` و`errors` **معًا**:

```graphql theme={"system"}
{
  history: postHistory(lastDays: 7)
  analytics: socialAnalytics(platforms: [INSTAGRAM])
}
```

```json theme={"system"}
{
  "data": {
    "history": { "history": [{ "id": "RkQ8uXg2jT7bNd1Wq0Ya", "status": "success", "post": "Hello world" }], "refId": "9d2a7c41f0b8e6d35a1c", "count": 1, "lastUpdated": "2026-09-24T12:00:00.000Z", "nextUpdate": "2026-09-24T12:00:00.000Z" },
    "analytics": null
  },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["analytics"],
      "extensions": { "status": 429 }
    }
  ]
}
```

نجح `history` وبياناته قابلة للاستخدام. فقط `analytics` يحتاج إلى إعادة المحاولة. لا تتجاهل الاستجابة بأكملها بسبب وجود `errors`، فذلك سيُهدر بيانات سبق أن دفعت مقابلها.

<h2 id="partial-success-on-multi-network-posts">
  النجاح الجزئي في المنشورات متعددة الشبكات
</h2>

قد ينجح المنشور المُرسَل إلى عدة شبكات على بعضها ويفشل على أخرى. لا يُبلَغ عن ذلك كخطأ GraphQL، لأن العملية نفسها نجحت؛ فقد نفّذت ما طلبته بالضبط وهي تخبرك بما حدث.

تفصل النتيجة بين النتائج الثلاث:

```graphql theme={"system"}
mutation {
  createPost(input: {
    post: "Hi"
    platforms: [FACEBOOK, INSTAGRAM]
    idempotencyKey: "multi-network-hi-001"
  }) {
    status
    postIds { platform postUrl }
    errors { platform message code }
    blocked { platform message }
  }
}
```

<ul class="custom-bullets">
  <li><code>postIds</code>: الشبكات التي تم النشر عليها، مع عناوين URL لمنشوراتها. حالات النجاح فقط.</li>
  <li><code>errors</code>: الشبكات التي فشل النشر عليها، مع السبب.</li>
  <li><code>blocked</code>: الشبكات التي أُوقفت قبل أي محاولة، على سبيل المثال بواسطة قاطع الدائرة الخاص بكل شبكة بعد حالات فشل حتمية متكررة. وهي منفصلة عن محاولات المزوّد التي أرجعت أخطاء.</li>
</ul>

تكون قيمة `status` هي `"error"` إذا فشلت **أي** شبكة، لذا فهي ليست مؤشرًا موثوقًا على أنه لم يُنشر شيء. اقرأ `postIds` لمعرفة ما تم نشره.

<h2 id="retries">
  إعادة المحاولة
</h2>

**لا تعيد GraphQL API المحاولة تلقائيًا أبدًا.** إذا فشل طلب، فلم تُجرَ أي محاولة أخرى بصمت نيابةً عنك.

يهم هذا أكثر ما يهم في الطفرات. يُتيح `createPost` الحقل `idempotencyKey`: أنشئ مفتاحًا فريدًا قبل المحاولة الأولى، ثم أعد استخدام المفتاح نفسه والحمولة المطابقة في كل إعادة محاولة. تُعيد إعادة المحاولة بعد استقرار الطلب النتيجة الأصلية بدلًا من تكرار عملية الكتابة. لا تنتقل إلى مفتاح جديد بعد استجابة غامضة.

يأخذ `boostFacebookPost` و`instagramBoostPost` أيضًا `idempotencyKey`، وهو يحمي أموالًا حقيقية. تُرجع إعادة المحاولة بالمفتاح نفسه والوسائط نفسها النتيجة الأصلية، مع العلامة `idempotentReplayed: true`، بدلًا من إنشاء إعلان ثانٍ ودفع ثمنه. يغطي المفتاح الواحد حسابك بأكمله على منصتي Meta كلتيهما، لذا لا تُعِد أبدًا استخدام مفتاح ترويج Facebook لترويج Instagram.

عند رفض مفتاح، تخبرك `extensions.status` بالسبب. يُرجع `createPost` الرمز 409 أثناء استمرار معالجة المحاولة الأولى، لذا انتظر وأعد المحاولة بالمفتاح نفسه، ويُرجع 400 عندما تختلف الحمولة عن المحاولة الأولى. تُرجع طفرات الترويج 409 في الحالتين، وكذلك عندما يكون المفتاح قد استُخدم لترويج على المنصة الأخرى.

عمليات الكتابة الأخرى، مثل `addComment`، ليس لها مفتاح منع تكرار. إذا فُقدت استجابتها، فتحقّق من الشبكة الاجتماعية أو من حالة API قبل أن تقرر ما إذا كانت محاولة أخرى آمنة.

هناك حدّان مختلفان يُبلغ كلاهما عن 429، ويتطلبان معالجة مختلفة. لا ترفض ميزانية الإرسال الحقول الجذرية إلا بعد أن تبدأ خمسة استدعاءات API بالفعل في الطلب نفسه، وتبدأ رسالتها بـ `Query exceeds the per-request dispatch budget`: قسّم تلك الحقول إلى طلبات لا يتجاوز كل منها خمسة، دون حاجة إلى الانتظار. أما أي 429 آخر فهو حد معدل أو حصة: انتظر `extensions.retryAfter` ثانية عند وجوده، وإلا فتراجع قبل إعادة المحاولة، وأعد المحاولة للحقول التي فشلت فقط. بالنسبة إلى 5xx في عملية **قراءة**، تكون إعادة المحاولة آمنة، مع استثناء واحد: `generatePost` هو استعلام، لكن إعادة المحاولة تستدعي مولّد الذكاء الاصطناعي مرة أخرى، وتُحتسب كاستدعاء API آخر، وتُرجع نصًا مختلفًا. وبالنسبة إلى 5xx في عملية كتابة دون منع تكرار، تحقّق مما إذا كانت قد نُفّذت قبل إعادة المحاولة.

<h2 id="common-statuses">
  الحالات الشائعة
</h2>

| `extensions.status` | المعنى | ما يجب فعله |
| - | - | - |
| 400 | إدخال غير صالح رفضته واجهة API لدينا | أصلح الطلب؛ لن تفيد إعادة المحاولة |
| 401 | مفتاح API مفقود أو غير صالح | تحقّق من ترويسة `Authorization` |
| 402 | الخطة لا تتضمن هذه الميزة | تحقّق من خطتك |
| 403 | المفتاح صالح لكنه غير مسموح له بهذا الإجراء | تحقّق من مفاتيح الملفات الشخصية والخطة |
| 404 | الشيء الذي طلبته غير موجود | تحقّق من المعرّف |
| 409 | مفتاح منع التكرار قيد الاستخدام: الطلب الأول لا يزال قيد التنفيذ، أو استُخدم مفتاح ترويج بوسائط مختلفة | إذا كان الطلب الأول لا يزال قيد التنفيذ، فانتظر وأعد المحاولة دون تغيير؛ وإلا فاستخدم مفتاحًا جديدًا للعملية الجديدة |
| 429 | حد المعدل أو الحصة أو ميزانية الإرسال | إذا ذكرت الرسالة ميزانية الإرسال، فقسّم الطلب. وإلا فانتظر `retryAfter`، أو تراجع إذا لم يكن موجودًا |
| 500 | حدث خطأ ما من جانبنا | أعد محاولة عملية القراءة (باستثناء `generatePost`، الذي يُفوتَر مرة أخرى)؛ أعد استخدام مفتاح منع التكرار نفسه حيثما كان مدعومًا، وإلا فتحقّق من عملية الكتابة قبل إعادة المحاولة |

الأخطاء التي تُطلقها GraphQL نفسها قبل التنفيذ، مثل الحقل غير المعروف أو نوع الوسيط الخاطئ أو قيمة التعداد غير الصالحة، ليس لها `extensions.status`. وتُرجع HTTP 400 أو 200 بحسب ترويسة `Accept` لديك، كما هو موضح أعلاه. وهي تعني أن الاستعلام نفسه خاطئ، ولم يُجرَ أي استدعاء API ولم تتم فوترته.
