معالجة الأخطاء
كل خطأ من كلمات له رمز قابل للقراءة آلياً، ورسالة قابلة للقراءة البشرية، ورمز حالة HTTP.
تنسيق استجابة الخطأ
عند الخطأ، حقل data يكون null وحقل error يحتوي على كائن منظّم:
error-response.json
{ "data": null, "error": { "code": "ERR_VALIDATION", "message": "Parameter 'letters' must be an integer between 1 and 20.", "field": "letters" }, "meta": { "requestId": "req_01j9abc...", "responseTimeMs": 2 }}| الحقل | النوع | الوصف |
|---|---|---|
| error.code | string | معرّف الخطأ القابل للقراءة آلياً. استخدمه للتعامل البرمجي مع الأخطاء. |
| error.message | string | وصف قابل للقراءة البشرية. آمن للعرض للمطوّرين، ليس للمستخدمين النهائيين. |
| error.field | string? | موجود في ERR_VALIDATION — اسم المعامل غير الصالح. |
| error.limit | number? | موجود في ERR_RATE_LIMIT_EXCEEDED — حدك اليومي. |
| error.resetAt | string? | موجود في ERR_RATE_LIMIT_EXCEEDED — طابع زمني ISO 8601 لوقت إعادة ضبط الحد. |
جميع رموز الأخطاء
| الرمز | HTTP | Description | الإجراء |
|---|---|---|---|
| ERR_AUTH_MISSING | 401 | لم يُقدَّم مفتاح API. | أضف ترويسة Authorization: Bearer ... أو x-api-key. |
| ERR_AUTH_INVALID | 401 | مفتاح API غير موجود. | المفتاح لا يطابق أي مفتاح نشط. تحقق من الأخطاء الإملائية. |
| ERR_AUTH_REVOKED | 401 | مفتاح API مُلغى. | أنشئ مفتاحاً جديداً من لوحة التحكم. |
| ERR_RATE_LIMIT_EXCEEDED | 429 | تجاوز حد الطلبات اليومي. | تحقق من ترويسة X-RateLimit-Reset لمعرفة وقت إعادة ضبط الحد. |
| ERR_VALIDATION | 400 | معاملات طلب غير صالحة. | رسالة الخطأ تحدد الحقل غير الصالح. |
| ERR_NOT_FOUND | 404 | المورد غير موجود. | الكلمة أو الجذر أو معرّف المورد المطلوب غير موجود. |
| ERR_PLAN_LIMIT | 403 | الميزة غير متاحة في الخطة الحالية. | رقّ للوصول إلى هذه النقطة أو المعامل. |
| ERR_INTERNAL | 500 | خطأ داخلي في الخادم. | حدث خطأ غير متوقع. أعد المحاولة بالتراجع الأسي. |
معالجة الأخطاء في SDK
يُصدّر SDK فئات أخطاء مُنمَّطة لكل رمز خطأ. استخدم فحوصات instanceof للتعامل الدقيق:
error-handling.ts
import { KalimaLab, RateLimitError, AuthError, NotFoundError, ValidationError, KalimaLabError,} from '@kalimalab/sdk'const client = new KalimaLab({ apiKey: process.env.KALIMALAB_API_KEY! })async function getWord(id: string) { try { return await client.words.get(id) } catch (err) { if (err instanceof RateLimitError) { // Specific: rate limit info available console.error(`Rate limit hit. Limit: ${err.limit}, resets at: ${err.resetAt}`) return null } if (err instanceof AuthError) { // Auth problem — check key console.error(`Auth error [${err.code}]: ${err.message}`) throw err } if (err instanceof NotFoundError) { // Word doesn't exist return null } if (err instanceof ValidationError) { // Bad parameters console.error(`Validation error on field: ${err.field}`) throw err } if (err instanceof KalimaLabError) { // Any other KalimaLab API error console.error(`API error ${err.status}: ${err.code}`) } throw err }}معالجة الأخطاء مع fetch الأصلي
typescript
async function fetchWord(id: string) { const res = await fetch(`https://api.kalimalab.com/v1/words/${id}`, { headers: { Authorization: `Bearer ${process.env.KALIMALAB_API_KEY}` }, }) const body = await res.json() if (!res.ok) { const { code, message } = body.error switch (code) { case 'ERR_NOT_FOUND': return null case 'ERR_RATE_LIMIT_EXCEEDED': throw new Error(`Rate limited until ${body.error.resetAt}`) case 'ERR_AUTH_MISSING': case 'ERR_AUTH_INVALID': case 'ERR_AUTH_REVOKED': throw new Error(`Authentication failed: ${message}`) default: throw new Error(`API error ${res.status}: ${code}`) } } return body.data}استراتيجية إعادة المحاولة
ليس كل خطأ يستحق إعادة المحاولة. هذا هو مصفوفة إعادة المحاولة الموصى بها:
| الخطأ / الحالة | إعادة المحاولة؟ | الاستراتيجية |
|---|---|---|
| 400 ERR_VALIDATION | No | أصلح معاملات الطلب. |
| 401 ERR_AUTH_* | No | أصلح مفتاح API. |
| 403 ERR_PLAN_LIMIT | No | رقّ خطتك. |
| 404 ERR_NOT_FOUND | No | المورد غير موجود. |
| 429 ERR_RATE_LIMIT | Yes | انتظر حتى الطابع الزمني X-RateLimit-Reset. |
| 500 ERR_INTERNAL | Yes | تراجع أسي: 1 ثانية، 2 ثانية، 4 ثوانٍ، ثم فشل. |
| Network timeout | Yes | أعد المحاولة حتى 3 مرات مع تراجع. |
ℹإعادة المحاولة التلقائية في SDK
يعيد SDK تلقائياً محاولة أخطاء 500 وانتهاء مهلة الشبكة حتى
maxRetries مرة (الافتراضي: 3) بالتراجع الأسي. لا يُعيد محاولة أخطاء 4xx.تطبيق التراجع الأسي
عند استدعاء API مباشرةً (دون SDK)، طبّق التراجع الأسي للأخطاء القابلة للإعادة. هذا يتجنب إغراق API ويزيد فرصة النجاح:
retry.ts
async function fetchWithRetry( url: string, options: RequestInit, maxRetries = 3,): Promise<Response> { let attempt = 0 while (attempt <= maxRetries) { const res = await fetch(url, options) // Success or a non-retryable client error — return immediately if (res.ok || (res.status >= 400 && res.status < 500 && res.status !== 429)) { return res } // 429: honour the Retry-After / X-RateLimit-Reset header if present if (res.status === 429) { const resetHeader = res.headers.get('X-RateLimit-Reset') const waitMs = resetHeader ? Math.max(0, Number(resetHeader) * 1000 - Date.now()) : 2 ** attempt * 1000 console.warn(`Rate limited. Waiting ${waitMs}ms before retry ${attempt + 1}.`) await new Promise((r) => setTimeout(r, waitMs)) } else { // 5xx: exponential backoff — 1s, 2s, 4s, 8s … const waitMs = 2 ** attempt * 1000 console.warn(`Server error ${res.status}. Waiting ${waitMs}ms before retry ${attempt + 1}.`) await new Promise((r) => setTimeout(r, waitMs)) } attempt++ } throw new Error(`Request failed after ${maxRetries} retries`)}// Usageconst res = await fetchWithRetry( 'https://api.kalimalab.com/v1/words?letters=3', { headers: { Authorization: `Bearer ${process.env.KALIMALAB_API_KEY}` } },)const { data } = await res.json()