Patterns de conception d'API JSON : construire de meilleures API REST
Une API bien conçue est un plaisir à utiliser. Une API mal conçue crée des bugs, de la frustration et de la dette technique. Ce guide couvre des patterns éprouvés pour concevoir des API REST JSON qui sont cohérentes, découvrables et maintenables.
Nommage des ressources
Les ressources sont des noms, pas des verbes. Utilisez des noms au pluriel pour les collections et des ressources individuelles via ID :
GET /api/users # Lister les utilisateurs
POST /api/users # Créer un utilisateur
GET /api/users/123 # Obtenir l'utilisateur 123
PUT /api/users/123 # Mettre Ă jour l'utilisateur 123
DELETE /api/users/123 # Supprimer l'utilisateur 123
Conventions de nommage :
- Utilisez des minuscules avec des tirets :
/api/blog-posts(pasblogPostsniblog_posts) - Imbriquez les ressources liées :
/api/users/123/orders - Limitez l'imbrication Ă 2 niveaux :
/api/users/123/orders/456(pas plus profond) - Ăvitez les verbes dans les URL :
/api/users/123/activateest acceptable pour les actions qui ne correspondent pas au CRUD
Enveloppe de réponse
Encapsulez les réponses dans une enveloppe cohérente :
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "Alice",
"email": "alice@example.com",
"createdAt": "2024-01-15T10:30:00Z"
}
},
"meta": {
"requestId": "req_abc123"
}
}
Pour les collections :
{
"data": [
{ "id": "123", "name": "Alice" },
{ "id": "456", "name": "Bob" }
],
"meta": {
"total": 142,
"page": 1,
"perPage": 20
}
}
Validez vos réponses API avec notre Validateur JSON pour vous assurer qu'elles correspondent à votre schéma.
Pagination
Trois approches courantes :
Basée sur l'offset (la plus simple)
GET /api/users?page=2&per_page=20
{
"data": [...],
"meta": {
"page": 2,
"perPage": 20,
"total": 142,
"totalPages": 8
}
}
Avantage : Simple, permet de sauter à n'importe quelle page. Inconvénient : Résultats incohérents avec des insertions/suppressions simultanées.
Basée sur le curseur (la plus fiable)
GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"meta": {
"hasNext": true,
"nextCursor": "eyJpZCI6MTQzfQ"
}
}
Avantage : Cohérente avec les modifications simultanées, performante sur les grands ensembles de données. Inconvénient : Impossible de sauter à des pages arbitraires.
Basée sur les clés (la plus performante)
GET /api/users?after_id=123&limit=20
Utilise l'ID du dernier élément (ou un autre champ trié) pour récupérer la page suivante. Similaire à la pagination par curseur mais avec des paramÚtres transparents.
Recommandation : Utilisez la pagination par curseur pour les flux en temps rĂ©el et les grands ensembles de donnĂ©es. Utilisez la pagination par offset pour les tableaux de bord d'administration oĂč la navigation par page compte.
Filtrage et tri
Filtrage
GET /api/users?status=active&role=admin
GET /api/users?created_after=2024-01-01
GET /api/users?search=alice
Pour les filtres complexes, envisagez un paramĂštre de requĂȘte dĂ©diĂ© :
GET /api/users?filter[status]=active&filter[role]=admin
Tri
GET /api/users?sort=name # Ascendant
GET /api/users?sort=-created_at # Descendant (préfixe avec -)
GET /api/users?sort=-created_at,name # Champs multiples
Gestion des erreurs
Des réponses d'erreur cohérentes sont critiques pour l'utilisabilité de l'API :
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"value": "not-an-email"
},
{
"field": "age",
"message": "Must be between 0 and 150",
"value": -5
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
Codes de statut HTTP Ă utiliser :
| Code | Signification | Quand |
|---|---|---|
| 200 | OK | GET, PUT réussis |
| 201 | Created | POST réussi |
| 204 | No Content | DELETE réussi |
| 400 | Bad Request | Erreurs de validation |
| 401 | Unauthorized | Auth manquante/invalide |
| 403 | Forbidden | Auth valide, permissions insuffisantes |
| 404 | Not Found | La ressource n'existe pas |
| 409 | Conflict | Ressource dupliquée, conflit de version |
| 422 | Unprocessable | Sémantiquement invalide |
| 429 | Too Many Requests | Limite de débit dépassée |
| 500 | Internal Error | Erreur serveur inattendue |
Versionnage
Trois approches :
Chemin d'URL (recommandé)
GET /api/v1/users
GET /api/v2/users
Avantage : Explicite, facile Ă router, facile Ă tester.
Basé sur les headers
GET /api/users
Accept: application/vnd.myapi.v2+json
Avantage : URL propres. Inconvénient : Plus difficile à tester, moins découvrable.
ParamĂštre de requĂȘte
GET /api/users?version=2
Avantage : Facile à tester. Inconvénient : Sémantique de paramÚtre optionnel.
Recommandation : Le versionnage par chemin d'URL est le choix le plus pratique. C'est explicite, cacheable et fonctionne avec tous les outils HTTP.
Gestion des dates et heures
Utilisez toujours ISO 8601 en UTC :
{
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T14:22:33Z",
"expiresAt": "2024-12-31T23:59:59Z"
}
N'utilisez jamais les timestamps Unix dans les rĂ©ponses API â ils sont ambigus (secondes vs millisecondes) et non lisibles par l'humain. Pour en savoir plus sur la gestion des timestamps, consultez notre guide des timestamps Unix.
Limitation de débit
Communiquez les limites de débit dans les headers de réponse :
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 67
X-RateLimit-Reset: 1705312800
Retry-After: 30
Renvoyez 429 Too Many Requests quand la limite est dépassée, avec un message d'erreur clair et un header Retry-After.
HATEOAS (optionnel mais puissant)
Incluez des liens vers les ressources et actions liées :
{
"data": {
"id": "123",
"name": "Alice",
"links": {
"self": "/api/users/123",
"orders": "/api/users/123/orders",
"avatar": "/api/users/123/avatar"
}
}
}
Cela rend votre API auto-documentée et réduit la construction d'URL cÎté client.
FAQ
Dois-je utiliser la spécification JSON:API ou concevoir mon propre format ?
La spĂ©cification JSON:API (jsonapi.org) fournit un standard complet, mais elle peut ĂȘtre verbeuse pour les API simples. Pour la plupart des projets, concevoir un format personnalisĂ© plus simple en suivant les patterns de ce guide est plus pratique. Utilisez JSON:API si vous avez besoin de bibliothĂšques clientes automatiques et d'un standard strict.
Comment gérer les mises à jour partielles (PATCH vs PUT) ?
Utilisez PUT pour le remplacement complet de la ressource (le client envoie tous les champs). Utilisez PATCH pour les mises à jour partielles (le client n'envoie que les champs modifiés). PATCH avec JSON Merge Patch (RFC 7396) est l'approche la plus simple : envoyez un objet JSON avec uniquement les champs à mettre à jour, et null pour supprimer un champ.
Ressources connexes
- Formateur JSON â Formatez les rĂ©ponses API pour la lisibilitĂ©
- Guide de validation de schĂ©ma JSON â Validez les charges utiles API avec JSON Schema
- Les tokens JWT expliquĂ©s â SĂ©curisez vos API avec les JSON Web Tokens