
واجهة برمجة التطبيقات (API) (واجهة برمجة التطبيقات) هي عقد بين مزود الخدمة وعملائه. تعتبر واجهة برمجة التطبيقات (API) المصممة جيدًا بديهية ومتسقة وسهلة الاستخدام. تؤدي واجهة برمجة التطبيقات (API) سيئة التصميم إلى إحباط المطورين وزيادة عبء الدعم ونقاط الضعف الأمنية والتغييرات الباهظة التكلفة.
واجهة برمجة التطبيقات (API) (واجهة برمجة التطبيقات) هي عقد بين مزود الخدمة وعملائه. تعتبر واجهة برمجة التطبيقات (API) المصممة جيدًا بديهية ومتسقة وسهلة الاستخدام. تؤدي واجهة برمجة التطبيقات (API) سيئة التصميم إلى إحباط المطورين وزيادة عبء الدعم ونقاط الضعف الأمنية والتغييرات الباهظة التكلفة.
واجهات برمجة التطبيقات (APIs) عبارة عن منتجات - قم بتصميمها بنفس العناية التي تتمتع بها واجهات المستخدم. سواء كنت تقوم ببناء REST أو GraphQL أو gRPC، تظل مبادئ التصميم الجيد لواجهة برمجة التطبيقات (API) ثابتة.
الموارد هي الكيانات الأساسية في نظامك. سميها بالأسماء وليس بالأفعال:
✅ GET /users — List users
✅ GET /users/123 — Get user by ID
✅ POST /users — Create user
✅ PATCH /users/123 — Partially update user
✅ PUT /users/123 — Replace user
✅ DELETE /users/123 — Delete user
❌ GET /getUser — Verb in URL
❌ POST /createUser — Verb in URL
❌ POST /users/create — Verb in URL path
❌ GET /users?action=delete — Action as query parameter
| الطريقة | الغرض | عاجز | آمنة | الجسم |
|---|---|---|---|---|
| الحصول على | استرداد أحد الموارد | نعم | نعم | لا |
| ** مشاركة ** | إنشاء مورد | لا | لا | نعم |
| ضع | استبدال كامل | نعم | لا | نعم |
| ** التصحيح ** | تحديث جزئي | لا | لا | نعم |
| حذف | إزالة أحد الموارد | نعم | لا | اختياري |
Idempotent: تؤدي الطلبات المتطابقة المتعددة إلى نفس نتيجة طلب واحد.
آمن: لا توجد آثار جانبية — يمكن تخزينها مؤقتًا وتكرارها بأمان.
naming_rules:
- "Use plural nouns: /users, /orders, /products"
- "Use kebab-case for multi-word: /order-items, /shipping-addresses"
- "Use lowercase throughout"
- "Nest resources logically: /users/123/orders"
- "Avoid deep nesting (max 2-3 levels)"
- "Use query parameters for filtering, sorting, pagination"
مثال التعشيش:
/users/123/orders — Orders belonging to user 123
/users/123/orders/456 — Specific order
/users/123/orders/456/items — Items in that order (okay)
/users/123/orders/456/items/789/details (too deep!)
يجب أن تؤدي التغييرات العاجلة إلى زيادة الإصدار:
إصدار URI (الأكثر شيوعًا):
https://api.example.com/v1/users
https://api.example.com/v2/users
إصدار الرأس:
Accept: application/vnd.example.v1+json
لا تقم مطلقًا بكسر التوافق مع الإصدارات السابقة داخل نفس الإصدار ما لم:
2xx Success:
200 OK: Generic success (GET, PATCH)
201 Created: Resource created (POST)
204 No Content: Success, no response body (DELETE)
3xx Redirection:
301 Moved Permanently
304 Not Modified (caching)
4xx Client Error:
400 Bad Request: Malformed request, validation error
401 Unauthorized: Missing or invalid authentication
403 Forbidden: Authenticated but not authorized
404 Not Found: Resource does not exist
405 Method Not Allowed: Wrong HTTP method
409 Conflict: Resource state conflict (duplicate, version mismatch)
422 Unprocessable Entity: Semantic validation failure
429 Too Many Requests: Rate limit exceeded
5xx Server Error:
500 Internal Server Error: Unexpected server failure
502 Bad Gateway: Upstream service failed
503 Service Unavailable: Temporary overload/maintenance
504 Gateway Timeout: Upstream service timed out
{
"data": {
"id": "user_123",
"email": "john@example.com",
"name": "John Doe",
"created_at": "2024-01-15T10:30:00Z"
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2024-01-15T10:30:00Z"
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body contains validation errors",
"details": [
{
"field": "email",
"message": "Email is required",
"code": "REQUIRED_FIELD"
},
{
"field": "age",
"message": "Age must be between 18 and 120",
"code": "INVALID_VALUE",
"constraints": {
"minimum": 18,
"maximum": 120
}
}
]
}
}
GET /users?page=2&per_page=20&sort=created_at:desc
{
"data": [ ... ],
"meta": {
"page": 2,
"per_page": 20,
"total": 100,
"total_pages": 5,
"count": 20
},
"links": {
"first": "/users?page=1&per_page=20",
"prev": "/users?page=1&per_page=20",
"next": "/users?page=3&per_page=20",
"last": "/users?page=5&per_page=20"
}
}
ترقيم الصفحات المستند إلى المؤشر (موصى به لمجموعات البيانات الكبيرة):
GET /users?cursor=eyJpZCI6IDUwMH0=&limit=20
{
"data": [ ... ],
"meta": {
"next_cursor": "eyJpZCI6IDUyMH0=",
"has_more": true
}
}
// Filtering
GET /users?role=admin&status=active
GET /orders?created_at[gte]=2024-01-01&total[gt]=100
// Sorting
GET /users?sort=name:asc,created_at:desc
// Searching
GET /users?search=john
// Field selection (sparse fields)
GET /users/123?fields=id,name,email
// PUT — Full replacement (requires all fields)
PUT /users/123
{
"email": "newemail@example.com",
"name": "John Updated",
"age": 31
}
// PATCH — Partial update (only send changed fields)
PATCH /users/123
{
"email": "newemail@example.com"
}
موصى به: OAuth 2.0 + OpenID Connect
POST /oauth/token
Content-Type: application/json
{
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"scope": "read write"
}
Response:
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}
GET /api/users
Authorization: Bearer eyJhbGciOi...
// Header
{
"alg": "RS256",
"typ": "JWT"
}
// Payload
{
"sub": "user_123",
"iss": "auth.example.com",
"iat": 1705312200,
"exp": 1705315800,
"scope": "read:users write:users",
"roles": ["admin"]
}
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1705315800
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
Content-Type: application/json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again in 3600 seconds.",
"retry_after": 3600
}
}
// Zod validation schema for API input
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email('Invalid email format'),
name: z.string().min(1, 'Name is required').max(100),
age: z.number().int().min(18).max(120).optional(),
role: z.enum(['user', 'admin', 'moderator']).default('user'),
tags: z.array(z.string()).max(10).optional(),
});
// Validation middleware
function validate(schema: ZodSchema) {
return (req, res, next) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(422).json({
error: {
code: 'VALIDATION_ERROR',
message: 'Validation failed',
details: result.error.issues.map(i => ({
field: i.path.join('.'),
message: i.message
}))
}
});
}
req.validatedBody = result.data;
next();
};
}
// CORS configuration
const corsOptions = {
origin: [
'https://app.example.com',
'https://admin.example.com',
],
methods: ['GET', 'POST', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-RateLimit-Remaining'],
credentials: true,
maxAge: 86400 // Preflight cache (24 hours)
};
app.use(cors(corsOptions));
openapi: 3.0.3
info:
title: User Management API
version: 2.0.0
description: API for managing users in the system
contact:
email: api-support@example.com
servers:
- url: https://api.example.com/v2
description: Production server
paths:
/users:
get:
summary: List all users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: per_page
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: A list of users
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
meta:
$ref: '#/components/schemas/PaginationMeta'
post:
summary: Create a new user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'422':
description: Validation error
components:
schemas:
User:
type: object
properties:
id:
type: string
email:
type: string
format: email
name:
type: string
created_at:
type: string
format: date-time
# Serve Swagger UI for API documentation
npm install -g swagger-ui-express
# Visit: https://api.example.com/docs
// Pact consumer-driven contract test
const { Pact } = require('@pact-foundation/pact');
describe('User API contract', () => {
const provider = new Pact({
consumer: 'Frontend App',
provider: 'User Service',
port: 1234,
});
beforeAll(() => provider.setup());
describe('GET /users/123', () => {
beforeAll(() => {
return provider.addInteraction({
state: 'User 123 exists',
uponReceiving: 'a request for user 123',
withRequest: {
method: 'GET',
path: '/users/123',
headers: { Authorization: 'Bearer valid-token' }
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: {
data: {
id: '123',
email: 'user@example.com',
name: 'Test User'
}
}
}
});
});
it('returns the user', async () => {
const response = await fetch('http://localhost:1234/users/123', {
headers: { Authorization: 'Bearer valid-token' }
});
expect(response.status).toBe(200);
});
afterEach(() => provider.verify());
});
afterAll(() => provider.finalize());
});
| الجانب | راحة | GraphQL |
|---|---|---|
| ** جلب البيانات ** | نقاط نهاية متعددة، استجابة ثابتة | نقطة نهاية واحدة، محددة من قبل العميل |
| ** الإفراط في الجلب ** | قد يعود ببيانات أكثر مما هو مطلوب | اطلب بالضبط ما تحتاجه |
| ** نقص الجلب ** | قد تحتاج إلى طلبات متعددة (N+1) | طلب واحد للبيانات المتداخلة |
| التخزين المؤقت | مدمج (التخزين المؤقت لـ HTTP، CDN) | مخصص (ذاكرة تخزين أبولو المؤقتة، الترحيل) |
| الأدوات | الناضجون (الضفيرة، ساعي البريد، المتصفحات) | النمو (GraphiQL، Apollo DevTools) |
| ** منحنى التعلم ** | منخفض | متوسط |
| الإصدار | إصدار URI | أضف الحقول، وتجاهل الحقول القديمة |
| تحميل الملف | أصلي (متعدد الأجزاء) | يتطلب معالجة خاصة |
| ** في الوقت الحقيقي ** | ويب سوكيت، إس إس إي | الاشتراكات |
version_policy:
- v1: Initial release (stable, deprecated)
- v2: Current version (active development)
- v3: Planned (future)
deprecation:
notice_period: 6 months
communication: email, API response header
sunset_header: true # Deprecation: true
transition:
new_features: v2 only
bug fixes: v1 critical only
migrations: provide migration guide
GET /v1/users/123
Sunset: Sat, 30 Nov 2024 00:00:00 GMT
Deprecation: true
Link: </v2/users/123>; rel="successor-version"
يتبع التصميم الجيد لواجهة برمجة التطبيقات هذه المبادئ:
واجهة برمجة التطبيقات (API) هي منتج. استثمر في تصميمه، وقم بتوثيقه بدقة، وقم بإصداره بعناية، وتعامل مع كل تغيير جذري بالخطورة التي يستحقها.
لا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.