معالجة الأخطاء
تستخدم واجهة TakeTheme البرمجية رموز استجابة HTTP المتعارف عليها للدلالة على نجاح الطلبات أو فشلها. ويشرح هذا الدليل صيغ استجابات الأخطاء وأفضل الممارسات للتعامل معها.
رموز حالة HTTP
| نطاق الرمز | المعنى |
|---|---|
2xx | نجاح — اكتمل الطلب بنجاح |
4xx | خطأ من العميل — هناك مشكلة في طلبك |
5xx | خطأ من الخادم — حدث خلل لدينا |
رموز الحالة الشائعة
| الرمز | الحالة | الوصف |
|---|---|---|
200 | OK | نجح الطلب |
201 | Created | أُنشئ المورد بنجاح |
204 | No Content | نجح الطلب دون إعادة محتوى |
400 | Bad Request | معاملات طلب غير صالحة |
401 | Unauthorized | مصادقة مفقودة أو غير صالحة |
403 | Forbidden | صلاحيات غير كافية |
404 | Not Found | المورد غير موجود |
409 | Conflict | تعارض في حالة المورد |
429 | Too Many Requests | تجاوز حد المعدل |
500 | Internal Server Error | خطأ من جانب الخادم |
503 | Service Unavailable | انقطاع مؤقت |
صيغة استجابة الخطأ
تتبع كل الأخطاء بنية JSON بسيطة تضم الحقلين status وmessage:
{
"status": 400,
"message": "\"email\" is required"
}
حقول كائن الخطأ
| الحقل | النوع | الوصف |
|---|---|---|
status | رقم | رمز حالة HTTP |
message | نص | وصف الخطأ بصيغة مقروءة |
وقد ت تضمن بعض استجابات الأخطاء حقولًا إضافية حسب نوع الخطأ.
أنواع الأخطاء
أخطاء المصادقة
عند فشل المصادقة بمفتاح الـ API:
{
"status": 401,
"message": "API key is required. Provide it via tt-api-key header or Authorization: Bearer header"
}
صيغة مفتاح غير صالحة:
{
"status": 401,
"message": "API key must start with tt_ prefix"
}
مفتاح مُبطل أو غير صالح:
{
"status": 401,
"message": "API key not found or has been revoked"
}
مفتاح منتهي الصلاحية:
{
"status": 401,
"message": "API key has expired"
}
أخطاء التفويض
صلاحيات غير كافية:
{
"status": 403,
"message": "API key does not have access to PRODUCTS"
}
الإجراء المطلوب غير ممنوح:
{
"status": 403,
"message": "API key cannot perform WRITE on PRODUCTS"
}
عنوان IP غير مدرج في القائمة المسموحة:
{
"status": 403,
"message": "Your IP address is not authorized to use this API key"
}
أخطاء التحقق
عند فشل التحقق من الطلب:
{
"status": 400,
"message": "\"email\" must be a valid email"
}
{
"status": 400,
"message": "\"price\" must be greater than or equal to 0"
}
أخطاء عدم الوجود
عندما لا يوجد المورد أو المسار:
{
"name": "Resource not found",
"message": "The page you are trying to access does not exist"
}
أخطاء حد المعدل
عند تجاوز حد المعدل:
{
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"status": 429
}
أخطاء الخادم
عند وقوع خطأ داخلي في الخادم:
{
"status": 500,
"message": "INTERNAL_SERVER_ERROR"
}
أخطاء التكرار
عند محاولة إنشاء مورد موجود بالفعل:
{
"status": 400,
"message": "slug and storeId combination with my-product and 65abc123def already exists."
}
التعامل مع الأخطاء
JavaScript/TypeScript
interface ApiError {
status: number;
message: string;
code?: string;
name?: string;
}
async function apiRequest<T>(
endpoint: string,
options?: RequestInit
): Promise<T> {
const response = await fetch(`https://api.taketheme.com/api/v1${endpoint}`, {
...options,
headers: {
"tt-api-key": API_KEY,
"Content-Type": "application/json",
...options?.headers,
},
});
const data = await response.json();
if (!response.ok) {
const error = data as ApiError;
switch (response.status) {
case 401:
throw new AuthenticationError(error.message);
case 403:
throw new ForbiddenError(error.message);
case 404:
throw new NotFoundError(error.message || error.name);
case 429:
throw new RateLimitError(error.message);
default:
throw new ApiError(error.message, error.status);
}
}
return data as T;
}
// Usage
try {
const product = await apiRequest("/products/prod_123");
} catch (error) {
if (error instanceof RateLimitError) {
// Wait and retry
await sleep(60000);
// Retry request...
} else if (error instanceof NotFoundError) {
console.log("Product not found");
} else if (error instanceof AuthenticationError) {
console.log("Check your API key");
} else {
console.error("Unexpected error:", error.message);
}
}
Python
import requests
from typing import Optional
class ApiError(Exception):
def __init__(self, message: str, status: int):
super().__init__(message)
self.message = message
self.status = status
class AuthenticationError(ApiError):
pass
class ForbiddenError(ApiError):
pass
class NotFoundError(ApiError):
pass
class RateLimitError(ApiError):
pass
def api_request(endpoint: str, method: str = 'GET', data: Optional[dict] = None) -> dict:
response = requests.request(
method,
f'https://api.taketheme.com/api/v1{endpoint}',
headers={
'tt-api-key': API_KEY,
'Content-Type': 'application/json'
},
json=data
)
result = response.json()
if not response.ok:
message = result.get('message', result.get('name', 'Unknown error'))
status = result.get('status', response.status_code)
if response.status_code == 401:
raise AuthenticationError(message, status)
elif response.status_code == 403:
raise ForbiddenError(message, status)
elif response.status_code == 404:
raise NotFoundError(message, status)
elif response.status_code == 429:
raise RateLimitError(message, status)
else:
raise ApiError(message, status)
return result
# Usage
try:
product = api_request('/products/prod_123')
except RateLimitError as e:
import time
time.sleep(60)
# Retry request...
except NotFoundError as e:
print("Product not found")
except AuthenticationError as e:
print("Check your API key")
except ApiError as e:
print(f"Error: {e.message} (Status: {e.status})")
مرجع رموز الأخطاء
المصادقة والتفويض
| رسالة الخطأ | الرمز | الوصف |
|---|---|---|
API key is required... | 401 | لم يُقدَّم مفتاح API |
API key must start with tt_ prefix | 401 | صيغة مفتاح غير صالحة |
API key not found or has been revoked | 401 | المفتاح غير موجود أو مُبطل |
API key has expired | 401 | المفتاح تجاوز تاريخ انتهائه |
API key usage limit has been reached | 429 | استُنفدت حصة الاستخدام |
API key does not have access to [RESOURCE] | 403 | صلاحية المورد غير ممنوحة |
API key cannot perform [ACTION] on [RESOURCE] | 403 | إذن الإجراء غير ممنوح |
Your IP address is not authorized... | 403 | عنوان IP خارج القائمة المسموحة |
حدود المعدل
| رسالة الخطأ | الشيفرة | الرمز | الوصف |
|---|---|---|---|
Rate limit exceeded | RATE_LIMIT_EXCEEDED | 429 | طلبات أكثر من اللازم |
التحقق
تُولَّد رسائل أخطاء التحقق من مخطط الطلب وتصف بدقة الحقل الذي فشل وسبب فشله. ومن الأنماط الشائعة:
| النمط | الوصف |
|---|---|
"[field]" is required | حقل مطلوب مفقود |
"[field]" must be a valid email | صيغة بريد غير صالحة |
"[field]" must be greater than [value] | القيمة دون الحد الأدنى |
"[field]" must be less than [value] | القيمة تتجاوز الحد الأقصى |
"[field]" must be one of [values] | قيمة غير مسموحة في القائمة |
"[field]" must be a string | نوع بيانات خاطئ |
الموارد
| رسالة الخطأ | الرمز | الوصف |
|---|---|---|
The page you are trying to access does not exist | 404 | المسار أو المورد غير موج ود |
[field] combination with [values] already exists. | 400 | إدخال مكرر |
أفضل الممارسات
1. تحقّق دائمًا من الأخطاء
// ✗ Bad: Ignoring potential errors
const { data } = await fetch("/products");
renderProducts(data);
// ✓ Good: Handling errors explicitly
const response = await fetch("/products");
if (!response.ok) {
const error = await response.json();
console.error("Error:", error.message);
return;
}
const { data } = await response.json();
renderProducts(data);
2. تعامل مع اختلاف رموز الحالة
async function handleApiError(response) {
const error = await response.json();
switch (response.status) {
case 400:
return `Validation error: ${error.message}`;
case 401:
return `Authentication failed: ${error.message}`;
case 403:
return `Permission denied: ${error.message}`;
case 404:
return "Resource not found";
case 429:
return "Rate limit exceeded. Please wait before retrying.";
case 500:
return "Server error. Please try again later.";
default:
return error.message || "An unexpected error occurred";
}
}
3. اعرض رسائل مفهومة للمستخدم
function getUserMessage(error) {
// Don't expose internal error details to users
if (error.status >= 500) {
return "Something went wrong. Please try again later.";
}
if (error.status === 429) {
return "Too many requests. Please wait a moment.";
}
// For client errors, the message is usually safe to show
return error.message;
}
4. طبّق إعادة المحاولة للأخطاء العابرة
async function fetchWithRetry(endpoint, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await apiRequest(endpoint);
return response;
} catch (error) {
// Only retry on server errors or rate limits
if (error.status !== 500 && error.status !== 503 && error.status !== 429) {
throw error; // Don't retry client errors
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error("Max retries exceeded");
}