SEPEHR.SYS

Starting SEPEHR.SYS…

Loading

سپهر محسنی

مهندس نرم‌افزار فول‌استک و هوش مصنوعی

NOTES.TXT ×

طراحی API‌های RESTful: بهترین شیوه‌ها برای ساخت API‌های مقیاس‌پذیر

5′ · ۱۴ دی ۱۴۰۴

یک API که به‌خوبی طراحی شده باشد، پایه و اساس هر اپلیکیشن موفقی است. این راهنما بهترین شیوه‌های طراحی API‌های RESTful را پوشش می‌دهد؛ API‌هایی که شهودی، مقیاس‌پذیر و قابل‌نگهداری باشند.

قراردادهای نام‌گذاری منابع

از اسم استفاده کنید، نه فعل

# Good - Resources are nouns
GET    /users              # List users
POST   /users              # Create user
GET    /users/123          # Get user
PUT    /users/123          # Update user
DELETE /users/123          # Delete user

# Bad - Verbs in URLs
GET    /getUsers
POST   /createUser
GET    /getUserById/123

منابع سلسله‌مراتبی

# Nested resources for relationships
GET    /users/123/orders           # User's orders
GET    /users/123/orders/456       # Specific order
POST   /users/123/orders           # Create order for user

# Alternative: Query parameters for filtering
GET    /orders?user_id=123         # Filter orders by user

<Callout type="info"> برای مجموعه‌ها از اسم‌های جمع (/users) و برای منابع مشخص از شناسه‌های تکی (/users/123) استفاده کنید. </Callout>

نام‌گذاری یک‌دست

# Use kebab-case for multi-word resources
GET /user-profiles
GET /order-items
GET /shipping-addresses

# Use snake_case for query parameters
GET /products?category_id=5&sort_by=price&sort_order=desc

متدهای HTTP و کدهای وضعیت

استفادهٔ درست از متدها

GET     - Retrieve resources (idempotent, cacheable)
POST    - Create new resources
PUT     - Replace entire resource (idempotent)
PATCH   - Partial update (not idempotent)
DELETE  - Remove resource (idempotent)
OPTIONS - Get allowed methods
HEAD    - Get headers only

مرجع کدهای وضعیت

// Success responses
200 OK              // Successful GET, PUT, PATCH
201 Created         // Successful POST (include Location header)
204 No Content      // Successful DELETE

// Client errors
400 Bad Request     // Invalid request body/parameters
401 Unauthorized    // Missing or invalid authentication
403 Forbidden       // Authenticated but not authorized
404 Not Found       // Resource doesn't exist
409 Conflict        // Resource conflict (duplicate, etc.)
422 Unprocessable   // Validation errors
429 Too Many Requests // Rate limit exceeded

// Server errors
500 Internal Error  // Unexpected server error
502 Bad Gateway     // Upstream service error
503 Service Unavailable // Temporary overload

طراحی درخواست و پاسخ

ساختار پاسخ یک‌دست

// Success response
{
  "data": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com",
    "created_at": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "request_id": "req_abc123"
  }
}

// Collection response with pagination
{
  "data": [
    { "id": 1, "name": "Product A" },
    { "id": 2, "name": "Product B" }
  ],
  "meta": {
    "total": 150,
    "page": 1,
    "per_page": 20,
    "total_pages": 8
  },
  "links": {
    "self": "/products?page=1",
    "next": "/products?page=2",
    "last": "/products?page=8"
  }
}

// Error response
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request contains invalid data",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      },
      {
        "field": "age",
        "message": "Must be at least 18"
      }
    ]
  },
  "meta": {
    "request_id": "req_xyz789"
  }
}

<Note title="نکتهٔ API"> همیشه برای دیباگ و پشتیبانی، یک شناسهٔ درخواست (request ID) در پاسخ‌ها قرار دهید. </Note>

فیلتر کردن، مرتب‌سازی و صفحه‌بندی

# Filtering
GET /products?category=electronics&brand=apple&min_price=100&max_price=500

# Sorting
GET /products?sort=price:asc,created_at:desc

# Pagination (offset-based)
GET /products?page=2&per_page=20

# Pagination (cursor-based - better for large datasets)
GET /products?cursor=eyJpZCI6MTAwfQ&limit=20

# Field selection (sparse fieldsets)
GET /users/123?fields=id,name,email

# Including related resources
GET /orders/123?include=user,items,shipping_address

نسخه‌بندی API

نسخه‌بندی در مسیر URL (توصیه‌شده)

GET /v1/users
GET /v2/users

# Clear and explicit
# Easy to route and cache
# Visible in logs and documentation

نسخه‌بندی با هدر

GET /users
Accept: application/vnd.myapi.v2+json

# Cleaner URLs
# More complex to implement
# Harder to test in browser

استراتژی منسوخ‌سازی نسخه‌ها

// Response headers for deprecated versions
{
  "headers": {
    "Deprecation": "Sun, 01 Jan 2025 00:00:00 GMT",
    "Sunset": "Sun, 01 Jul 2025 00:00:00 GMT",
    "Link": "</v2/users>; rel=\"successor-version\""
  }
}

احراز هویت و کنترل دسترسی

احراز هویت با JWT

// Request with Bearer token
GET /api/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// Token structure
{
  "header": {
    "alg": "RS256",
    "typ": "JWT"
  },
  "payload": {
    "sub": "user_123",
    "email": "user@example.com",
    "roles": ["user", "admin"],
    "iat": 1704067200,
    "exp": 1704153600
  }
}

احراز هویت با API Key

// Header-based (recommended)
GET /api/data
X-API-Key: sk_live_abc123xyz

// Query parameter (less secure - visible in logs)
GET /api/data?api_key=sk_live_abc123xyz

اسکوپ‌های OAuth 2.0

# Define granular permissions
read:users      - Read user data
write:users     - Create/update users
delete:users    - Delete users
read:orders     - Read order data
admin           - Full access

# Token with scopes
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read:users read:orders"
}

محدودیت نرخ درخواست (Rate Limiting)

هدرهای پیاده‌سازی

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1704067200

# When rate limited
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200

استراتژی‌های Rate Limit

// Sliding window implementation
const rateLimiter = {
  // Per-user limits
  authenticated: {
    requests: 1000,
    window: '1 hour'
  },
  // Per-IP limits for unauthenticated
  anonymous: {
    requests: 100,
    window: '1 hour'
  },
  // Per-endpoint limits
  endpoints: {
    'POST /auth/login': { requests: 5, window: '1 minute' },
    'POST /users': { requests: 10, window: '1 hour' }
  }
};

مدیریت خطا

پاسخ خطای جامع

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "The requested user was not found",
    "details": {
      "resource_type": "User",
      "resource_id": "123"
    },
    "documentation_url": "https://api.example.com/docs/errors#RESOURCE_NOT_FOUND",
    "request_id": "req_abc123"
  }
}

کاتالوگ کدهای خطا

const errorCodes = {
  // Authentication errors (1xxx)
  INVALID_CREDENTIALS: { status: 401, message: 'Invalid email or password' },
  TOKEN_EXPIRED: { status: 401, message: 'Authentication token has expired' },
  INSUFFICIENT_PERMISSIONS: { status: 403, message: 'You do not have permission' },
  
  // Validation errors (2xxx)
  VALIDATION_ERROR: { status: 422, message: 'Request validation failed' },
  INVALID_FORMAT: { status: 400, message: 'Invalid request format' },
  
  // Resource errors (3xxx)
  RESOURCE_NOT_FOUND: { status: 404, message: 'Resource not found' },
  RESOURCE_CONFLICT: { status: 409, message: 'Resource already exists' },
  
  // Rate limiting (4xxx)
  RATE_LIMIT_EXCEEDED: { status: 429, message: 'Too many requests' },
  
  // Server errors (5xxx)
  INTERNAL_ERROR: { status: 500, message: 'An unexpected error occurred' },
  SERVICE_UNAVAILABLE: { status: 503, message: 'Service temporarily unavailable' },
};

HATEOAS و Hypermedia

پاسخ‌های خودتوصیف‌گر

{
  "data": {
    "id": 123,
    "status": "pending",
    "total": 99.99
  },
  "links": {
    "self": { "href": "/orders/123" },
    "customer": { "href": "/users/456" },
    "items": { "href": "/orders/123/items" }
  },
  "actions": {
    "cancel": {
      "href": "/orders/123/cancel",
      "method": "POST",
      "title": "Cancel this order"
    },
    "pay": {
      "href": "/orders/123/pay",
      "method": "POST",
      "title": "Process payment"
    }
  }
}

مستندسازی API

مشخصات OpenAPI

openapi: 3.0.3
info:
  title: My API
  version: 1.0.0
  description: A sample API

paths:
  /users:
    get:
      summary: List all users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email

جمع‌بندی

API‌هایی که خوب طراحی شده باشند، شهودی، یک‌دست و مقیاس‌پذیرند. با پیروی از این بهترین شیوه‌ها — نام‌گذاری درست منابع، کدهای وضعیت مناسب، مدیریت خطای جامع و مستندسازی شفاف — API‌هایی می‌سازید که توسعه‌دهندگان عاشق کار با آن‌ها می‌شوند.

نکات کلیدی:

  • برای منابع از اسم استفاده کنید و برای عملیات از متدهای HTTP
  • کدهای وضعیت مناسب برگردانید
  • نسخه‌بندی اصولی را از همان ابتدا پیاده‌سازی کنید
  • پاسخ‌های خطای جامع طراحی کنید
  • همه‌چیز را با OpenAPI مستند کنید

این یادداشت ترجمهٔ فارسی نوشتهٔ خودم است — نسخهٔ اصلی (انگلیسی) در dev.to