Files
wevia-brain/knowledge/deep/api-design-patterns.md
2026-04-12 23:01:36 +02:00

4.6 KiB
Executable File

API Design Patterns — Guide Expert

REST API Best Practices

Nommage des URLs

# BON — Resource-oriented, pluriel, hiérarchique
GET    /api/v1/users                    # Liste
GET    /api/v1/users/123                # Détail
POST   /api/v1/users                    # Créer
PUT    /api/v1/users/123                # Remplacer
PATCH  /api/v1/users/123                # Modifier partiellement
DELETE /api/v1/users/123                # Supprimer
GET    /api/v1/users/123/orders         # Sous-resource
GET    /api/v1/users/123/orders/456     # Détail sous-resource

# MAUVAIS
GET    /api/getUser/123                 # Verbe dans l'URL
POST   /api/user/create                 # Redondant avec POST
GET    /api/v1/User                     # Singulier, majuscule

Status Codes

Code Usage
200 OK — GET/PUT/PATCH réussi
201 Created — POST réussi
204 No Content — DELETE réussi
400 Bad Request — Input invalide
401 Unauthorized — Pas d'auth
403 Forbidden — Auth OK mais pas les permissions
404 Not Found
409 Conflict — Doublon, état incohérent
422 Unprocessable Entity — Validation échouée
429 Too Many Requests — Rate limit
500 Internal Server Error
503 Service Unavailable — Maintenance

Pagination

// Cursor-based (recommandé pour les grands datasets)
GET /api/v1/contacts?limit=50&cursor=eyJpZCI6MTIzNH0=

Response:
{
  "data": [...],
  "meta": {
    "total": 6650000,
    "limit": 50,
    "next_cursor": "eyJpZCI6MTI4NH0=",
    "has_more": true
  }
}

// Offset-based (simple mais lent sur gros volumes)
GET /api/v1/contacts?page=5&per_page=50

Error Format Standard

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "La validation a échoué",
    "details": [
      {
        "field": "email",
        "message": "Format email invalide",
        "code": "INVALID_FORMAT"
      },
      {
        "field": "name",
        "message": "Le nom est requis",
        "code": "REQUIRED"
      }
    ],
    "request_id": "req_abc123",
    "timestamp": "2026-02-17T10:30:00Z"
  }
}

Rate Limiting Headers

X-RateLimit-Limit: 1000          # Max requêtes par fenêtre
X-RateLimit-Remaining: 742       # Requêtes restantes
X-RateLimit-Reset: 1708171200    # Timestamp de reset
Retry-After: 60                  # Secondes à attendre (si 429)

Authentication Patterns

# Bearer Token (recommandé)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# API Key (simple, pour server-to-server)
X-API-Key: wevads_live_abc123def456

# Basic Auth (legacy, HTTPS obligatoire)
Authorization: Basic base64(username:password)

Versioning Strategies

Strategy Exemple Avantages Inconvénients
URL path /api/v1/users Clair, simple URL change
Header Accept: application/vnd.api.v2+json URL stable Moins visible
Query param /api/users?version=2 Simple Pollue les params

Webhook Design

// Webhook payload standard WEVADS
{
  "event": "conversion.created",
  "timestamp": "2026-02-17T10:30:00Z",
  "data": {
    "conversion_id": "conv_abc123",
    "offer_id": 42,
    "payout": 27.50,
    "currency": "USD",
    "sub1": "camp_123",
    "sub2": "creative_456",
    "sub3": "user_789"
  },
  "signature": "sha256=abc123..."
}

// Signature verification (HMAC)
$expectedSig = 'sha256=' . hash_hmac('sha256', $rawBody, $webhookSecret);
if (!hash_equals($expectedSig, $receivedSig)) {
    http_response_code(401);
    die('Invalid signature');
}

Patterns d'intégration WEVADS

CX3 Ads (CAKE) API

# Pull conversions
GET https://api.cx3ads.com/conversions?start_date=2026-02-17&end_date=2026-02-17&affiliate_id=10805
Headers: Authorization: Bearer {api_key}

# Response
{
  "conversions": [
    {
      "conversion_id": "...",
      "offer_id": 42,
      "payout": 27.50,
      "sub1": "wevads_camp_123",
      "sub2": "creative_456",
      "sub3": "contact_789",
      "datetime": "2026-02-17T14:30:00Z"
    }
  ]
}

Ollama API (local LLM)

# Chat completion
POST http://88.198.4.195:11434/api/chat
{
  "model": "deepseek-r1:32b",
  "messages": [
    {"role": "system", "content": "Tu es WEVIA..."},
    {"role": "user", "content": "Question..."}
  ],
  "stream": false,
  "options": {"temperature": 0.7}
}

# Generate embedding
POST http://88.198.4.195:11434/api/embeddings
{
  "model": "nomic-embed-text",
  "prompt": "Texte à embedder"
}
// Response: {"embedding": [0.123, -0.456, ...]}  // 768 dimensions

# List models
GET http://88.198.4.195:11434/api/tags