Utilisation de l'API — Conventions REST
Authentifier les requêtes, pagination, filtres, multi-tenant automatique et format d'erreur unifié.
Utilisation de l'API — Conventions REST
Toutes les requêtes post-auth passent par la Public API (
ws-back-api :3005). Ce chapitre couvre les conventions REST, l'authentification des requêtes, la pagination et le multi-tenant.
Concepts clés
- Bearer + enriched : double authentification obligatoire pour les appels frontend.
- API Key : alternative pour les backends serveur-à-serveur.
- WID : identifiant court préféré dans les URLs et les paramètres.
- Filtrage automatique : le backend filtre selon le scope du token — vous ne filtrez jamais manuellement.
- Pagination : page-based (page + limit), pas cursor-based.
Authentification des requêtes
Méthode 1 — Bearer JWT + enriched token (frontend)
Une requête vers les services downstream doit porter deux tokens :
httpAuthorization: Bearer <keycloak_access_token> (RS256, émis par Keycloak) x-enriched-token: <wakastart_token> (HS256, émis par ws-serv-token)
Sans x-enriched-token, la réponse est 401 Token enrichi manquant ou invalide.
Implémentation recommandée — proxy serveur Next.js :
typescript// app/api/proxy/[...path]/route.ts import { cookies } from "next/headers"; import { NextRequest, NextResponse } from "next/server"; export async function GET( req: NextRequest, { params }: { params: { path: string[] } } ) { const cookieStore = await cookies(); const accessToken = cookieStore.get("keycloak_token")?.value; const enrichedToken = cookieStore.get("wakastart_token")?.value; if (!accessToken || !enrichedToken) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } const apiUrl = `${process.env.WAKASTART_API_URL}/api/${params.path.join("/")}`; const url = new URL(apiUrl); req.nextUrl.searchParams.forEach((value, key) => { url.searchParams.set(key, value); }); const response = await fetch(url.toString(), { method: req.method, headers: { "Authorization": `Bearer ${accessToken}`, "x-enriched-token": enrichedToken, "Content-Type": "application/json", }, }); const data = await response.json(); return NextResponse.json(data, { status: response.status }); }
Depuis votre frontend React :
typescript// lib/api.ts — utilise le proxy qui gère l'auth async function apiGet<T>(path: string, params?: Record<string, string>): Promise<T> { const url = new URL(`/api/proxy/${path}`, window.location.origin); if (params) { Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v)); } const res = await fetch(url.toString()); if (!res.ok) throw new ApiError(res.status, await res.json()); return res.json(); } // Usage : const users = await apiGet<UserList>("config/users", { page: "1", limit: "20" });
Méthode 2 — API Key (backend serveur-à-serveur)
Les API Keys remplacent entièrement la paire Bearer+enriched. Elles sont scopées à un Customer.
typescriptconst response = await fetch(`${WAKASTART_API_URL}/api/config/users`, { headers: { "x-api-key": "sk_live_...", "Content-Type": "application/json", }, });
Les API Keys sont des secrets — ne les exposez jamais côté frontend, ne les committez jamais.
Conventions REST
| Convention | Détail |
|---|---|
| Verbes HTTP | GET (lecture), POST (création), PATCH (mise à jour partielle), PUT (remplacement), DELETE (suppression) |
| Format date | ISO 8601 avec timezone : 2026-05-19T10:30:00.000Z |
| Identifiants dans les URLs | Préférer les WIDs (/config/users/WKST05) aux UUIDs |
| Content-Type | application/json sur tous les POST/PATCH/PUT |
| Encodage | UTF-8 obligatoire |
| Nullabilité | Les champs absents ne sont pas retournés (pas de null explicite sauf si documenté) |
Format d'erreur unifié
json{ "statusCode": 403, "message": "Niveau d'administration insuffisant. Requis: CustomerAdmin, Actuel: User", "error": "Forbidden" }
Pour les erreurs de validation (400) :
json{ "statusCode": 400, "message": [ "email must be an email", "firstName should not be empty" ], "error": "Bad Request" }
Pagination
Tous les endpoints de liste supportent la pagination par page :
httpGET /api/config/users?page=1&limit=20
json{ "data": [ { "id": "uuid", "wid": "WKST05", "email": "john@acme.com" } ], "meta": { "total": 142, "page": 1, "limit": 20, "totalPages": 8 } }
Paramètres :
| Param | Défaut | Max | Description |
|---|---|---|---|
page | 1 | — | Numéro de page (1-indexed) |
limit | 20 | 100 | Nombre d'éléments par page |
Pattern avec TanStack Query :
typescriptimport { useQuery } from "@tanstack/react-query"; function useUsers(page: number) { return useQuery({ queryKey: ["users", page], queryFn: () => apiGet<UserList>("config/users", { page: String(page), limit: "20" }), placeholderData: (prev) => prev, }); }
Filtres communs
httpGET /api/config/users?search=john&isActive=true&page=1&limit=20 GET /api/config/customers?networkId=NET001&page=1 GET /api/invitations/sent?status=PENDING&page=1&limit=10
Multi-tenant automatique
Les données sont automatiquement filtrées selon le scope du token :
adminLevel | Portée des données retournées |
|---|---|
WakaAdmin | Toute la plateforme |
OwnerAdmin | Son Partner entier |
NetworkAdmin | Son Network + tous ses Customers |
CustomerAdmin | Son Customer uniquement |
User | Son propre profil |
Vous n'avez pas besoin de filtrer manuellement. Si un CustomerAdmin appelle GET /api/config/users, il ne voit que les utilisateurs de son Customer.
Runtime config
Pour charger le thème, les langues et le branding de votre app en un seul appel :
httpGET /api/apps/{appWid}/runtime-config Authorization: Bearer <token> x-enriched-token: <wakaToken>
json{ "theme": { "id": "uuid", "name": "Default", "cssUrl": "https://storage.wakastart.app/themes/default.css" }, "languages": [ { "code": "fr", "name": "Français", "isDefault": true, "i18nUrl": "https://storage.wakastart.app/i18n/fr.json" } ], "branding": { "logoLightUrl": "https://storage.wakastart.app/logos/acme-light.png", "logoDarkUrl": "https://storage.wakastart.app/logos/acme-dark.png", "faviconUrl": "https://storage.wakastart.app/favicons/acme.ico" } }
Bonnes pratiques
- Proxy serveur : ne laissez jamais le browser manipuler les cookies ou les tokens directement.
- Gestion des 401 : tenter un refresh token, puis redirect vers login. Jamais de boucle infinie.
- Préférer les WIDs : dans vos routes et vos paramètres, les WIDs (
WKST05) sont plus lisibles que les UUIDs. - Limit max 100 : ne dépassez pas
limit=100par page. - TanStack Query : utilisez
staleTimepour éviter les re-fetches inutiles (5-30s selon la criticité).
Pièges classiques
- Header
x-enriched-tokenabsent : toutes les requêtes frontend retournent401. - Filtrage manuel inutile : ajouter
customerId=xxxmanuellement alors que le backend filtre déjà. limit=1000: timeout garanti sur les gros tenants. Paginez proprement.- CORS sur les appels directs : si votre frontend appelle directement l'API sans proxy, vous aurez des erreurs CORS.
Aller plus loin
- Headers & Rate limits : headers requis, idempotence, CORS, throttling
- Référence des endpoints : tableau complet de toutes les routes
- Erreurs HTTP : codes HTTP et messages détaillés