veza/apps/web/FRONTEND_INTEGRATION.md

12 KiB

Frontend Integration Guide — Veza Backend API

Version: 1.2.0
Date: 2025-01-27
Base URL: http://localhost:8080/api/v1 (configurable via VITE_API_URL)


Table des Matières

  1. Configuration
  2. Authentification
  3. Format des Réponses
  4. Gestion des Erreurs
  5. Codes d'Erreur
  6. Exemples de Requêtes
  7. Health Checks

Configuration

Variables d'Environnement Frontend

# .env.local ou .env.production
VITE_API_URL=http://localhost:8080/api/v1
VITE_WS_URL=ws://localhost:8081/ws
VITE_STREAM_URL=ws://localhost:8082/stream

Headers Requis

Toutes les requêtes authentifiées doivent inclure :

{
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
}

Authentification

Format du Token JWT

Le token JWT est fourni dans le header Authorization :

Authorization: Bearer <token>

Endpoints d'Authentification

POST /auth/login

Request :

{
  "email": "user@example.com",
  "password": "password123",
  "remember_me": false
}

Response Success (200) :

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 3600,
    "token_type": "Bearer",
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "user@example.com",
      "username": "username",
      "role": "user"
    }
  }
}

Response Error (401) :

{
  "success": false,
  "data": null,
  "error": {
    "code": 1000,
    "message": "Invalid credentials",
    "request_id": "req-123",
    "timestamp": "2025-01-27T10:00:00Z"
  }
}

POST /auth/register

Request :

{
  "email": "user@example.com",
  "password": "password123",
  "username": "username"
}

POST /auth/refresh

Request :

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

GET /auth/me

Headers :

Authorization: Bearer <token>

Response Success (200) :

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "username": "username",
    "role": "user",
    "created_at": "2025-01-27T10:00:00Z"
  }
}

Format des Réponses

Réponse Succès

Toutes les réponses de succès suivent ce format :

{
  "success": true,
  "data": { ... },
  "message": "Optional success message"
}

Exemples :

  • GET /tracks/:id :
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "Track Title",
    "artist": "Artist Name",
    "duration": 180.5,
    "status": "ready"
  }
}
  • POST /tracks (201 Created) :
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "New Track",
    "status": "processing"
  },
  "message": "Track uploaded successfully"
}

Réponse Erreur

Toutes les réponses d'erreur suivent ce format standardisé :

{
  "success": false,
  "data": null,
  "error": {
    "code": 2000,
    "message": "Validation failed",
    "details": [
      {
        "field": "email",
        "message": "Email is required"
      }
    ],
    "request_id": "req-123",
    "timestamp": "2025-01-27T10:00:00Z",
    "context": {
      "user_id": "550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

Champs :

  • code : Code d'erreur numérique (voir Codes d'Erreur)
  • message : Message d'erreur lisible
  • details : Détails de validation (optionnel, pour erreurs 400)
  • request_id : ID de requête pour corrélation des logs (optionnel)
  • timestamp : Timestamp ISO 8601
  • context : Contexte additionnel (optionnel)

Gestion des Erreurs

TypeScript Interface

interface APIError {
  code: number;
  message: string;
  details?: Array<{
    field: string;
    message: string;
  }>;
  request_id?: string;
  timestamp: string;
  context?: Record<string, any>;
}

interface APIResponse<T> {
  success: boolean;
  data: T | null;
  error?: APIError;
}

Helper Function

async function apiRequest<T>(
  endpoint: string,
  options?: RequestInit
): Promise<T> {
  const token = localStorage.getItem('access_token');
  
  const response = await fetch(`${import.meta.env.VITE_API_URL}${endpoint}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(token && { Authorization: `Bearer ${token}` }),
      ...options?.headers,
    },
  });

  const data: APIResponse<T> = await response.json();

  if (!data.success || data.error) {
    throw new APIError(data.error!);
  }

  return data.data!;
}

class APIError extends Error {
  constructor(public error: APIError) {
    super(error.message);
    this.name = 'APIError';
  }
}

Gestion des Codes HTTP

Code HTTP Signification Action Frontend
200 Succès Traiter data
201 Créé Traiter data
400 Bad Request Afficher error.message + error.details
401 Unauthorized Rediriger vers login, rafraîchir token
403 Forbidden Afficher erreur, vérifier permissions
404 Not Found Afficher "Ressource non trouvée"
409 Conflict Afficher error.message
422 Unprocessable Entity Afficher error.message + error.details
429 Too Many Requests Afficher "Trop de requêtes", attendre
500 Internal Server Error Logger request_id, afficher message générique
502 Bad Gateway Afficher "Service temporairement indisponible"

Codes d'Erreur

Authentication & Authorization (1000-1999)

Code Message HTTP Status
1000 Invalid credentials 401
1001 Token expired 401
1002 Token invalid 401
1003 Forbidden 403
1004 Unauthorized 401

Validation (2000-2999)

Code Message HTTP Status
2000 Validation failed 400
2001 Required field 400
2002 Invalid format 400
2003 Out of range 400

Resource (3000-3999)

Code Message HTTP Status
3000 Not found 404
3001 Already exists 409
3002 Conflict 409

Business Logic (4000-4999)

Code Message HTTP Status
4000 Operation not allowed 422
4005 Quota exceeded 403

Rate Limiting (5000-5099)

Code Message HTTP Status
5000 Rate limit exceeded 429

Internal (9000-9999)

Code Message HTTP Status
9000 Internal error 500
9001 Database error 500

Exemples de Requêtes

Health Check

curl -X GET http://localhost:8080/api/v1/health

Response :

{
  "status": "ok"
}

Login

curl -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "password123",
    "remember_me": false
  }'

Response Success :

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 3600,
    "token_type": "Bearer",
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "user@example.com",
      "username": "username",
      "role": "user"
    }
  }
}

Response Error (Invalid Credentials) :

{
  "success": false,
  "data": null,
  "error": {
    "code": 1000,
    "message": "Invalid credentials",
    "request_id": "req-123",
    "timestamp": "2025-01-27T10:00:00Z"
  }
}

Get User Profile

curl -X GET http://localhost:8080/api/v1/auth/me \
  -H "Authorization: Bearer <token>"

Response Success :

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "username": "username",
    "role": "user",
    "created_at": "2025-01-27T10:00:00Z"
  }
}

Get Track

curl -X GET http://localhost:8080/api/v1/tracks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer <token>"

Response Success :

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "Track Title",
    "artist": "Artist Name",
    "duration": 180.5,
    "status": "ready",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": "2025-01-27T10:00:00Z"
  }
}

Response Error (Not Found) :

{
  "success": false,
  "data": null,
  "error": {
    "code": 3000,
    "message": "track not found",
    "request_id": "req-123",
    "timestamp": "2025-01-27T10:00:00Z"
  }
}

Create Playlist

curl -X POST http://localhost:8080/api/v1/playlists \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My Playlist",
    "description": "A great playlist",
    "is_public": true
  }'

Response Success (201) :

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "My Playlist",
    "description": "A great playlist",
    "is_public": true,
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": "2025-01-27T10:00:00Z"
  }
}

Response Error (Validation) :

{
  "success": false,
  "data": null,
  "error": {
    "code": 2000,
    "message": "Validation failed",
    "details": [
      {
        "field": "title",
        "message": "Title is required"
      }
    ],
    "request_id": "req-123",
    "timestamp": "2025-01-27T10:00:00Z"
  }
}

Health Checks

GET /health

Health check simple (toujours 200 si serveur actif).

curl -X GET http://localhost:8080/api/v1/health

Response :

{
  "status": "ok"
}

GET /readyz

Readiness probe (vérifie DB, Redis, RabbitMQ).

curl -X GET http://localhost:8080/api/v1/readyz

Response Success (200) :

{
  "status": "ready",
  "database": "ok",
  "redis": "ok",
  "rabbitmq": "ok"
}

Response Degraded (200) :

{
  "status": "degraded",
  "database": "ok",
  "redis": "unavailable",
  "rabbitmq": "unavailable"
}

Note : /readyz retourne toujours 200 (même en mode dégradé) pour permettre au service de démarrer même si Redis/RabbitMQ sont indisponibles.

GET /status

Status détaillé (DB, Redis, Chat Server, Stream Server).

curl -X GET http://localhost:8080/api/v1/status

Response :

{
  "status": "ok",
  "database": {
    "status": "ok",
    "latency_ms": 5
  },
  "redis": {
    "status": "ok",
    "latency_ms": 2
  },
  "chat_server": {
    "status": "ok",
    "url": "http://localhost:8081"
  },
  "stream_server": {
    "status": "ok",
    "url": "http://localhost:8082"
  }
}

Notes Importantes

CORS

En production, CORS_ALLOWED_ORIGINS doit être configuré. Le Frontend doit être dans la liste des origines autorisées.

Rate Limiting

  • Login : 5 tentatives par minute
  • Global : 100 requêtes par minute (configurable)

Les headers de rate limiting sont retournés :

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1234567890

Pagination

Les listes (tracks, playlists, etc.) supportent la pagination :

GET /tracks?page=1&limit=20

Response :

{
  "success": true,
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "total_pages": 5,
    "has_next": true,
    "has_previous": false
  }
}

UUID Format

Tous les IDs sont des UUID v4 :

550e8400-e29b-41d4-a716-446655440000

Support

  • Documentation API : /swagger/index.html (Swagger UI)
  • Issues : GitHub Issues

Last Updated: 2025-01-27