REST (Representational State Transfer) fournit un style architectural fondamental pour la création de services web. Cependant, il laisse de nombreux aspects du formatage des requêtes et des réponses non définis. Cette ambiguïté peut entraîner des incohérences, une augmentation des frais de développement et une courbe d'apprentissage plus raide pour les consommateurs d'API. Entrez JSON:API, une spécification qui fournit une approche normalisée et basée sur des conventions pour la création d'API en JSON.
Ce guide complet propose une plongée en profondeur dans la spécification JSON:API, explorant ses concepts de base, sa structure et ses fonctionnalités puissantes. Nous allons disséquer ses mécanismes pour récupérer, créer, mettre à jour et supprimer des ressources, gérer les relations, gérer les erreurs et optimiser le transfert de données, vous dotant des connaissances nécessaires pour concevoir et consommer des API robustes et efficaces.
Vous voulez une plateforme intégrée, tout-en-un, pour que votre équipe de développeurs travaille ensemble avec une productivité maximale ?
Apidog répond à toutes vos demandes et remplace Postman à un prix beaucoup plus abordable !
Pourquoi JSON:API ? Explication :
Avant de plonger dans les subtilités techniques, il est crucial de comprendre les problèmes que JSON:API vise à résoudre. Sans convention partagée, les développeurs d'API passent souvent beaucoup de temps à débattre :
- Structure de la charge utile : Comment les ressources et leurs attributs doivent-ils être représentés ?
- Représentation des relations : Comment les liens entre les différentes ressources doivent-ils être transmis ?
- Stratégies de récupération de données : Comment les clients peuvent-ils demander des champs spécifiques, inclure des ressources connexes, trier, paginer et filtrer les données ?
- Rapports d'erreurs : Quel format les messages d'erreur doivent-ils suivre ?
JSON:API y répond en définissant un format clair et cohérent pour les requêtes et les réponses. Cette normalisation offre plusieurs avantages clés :
- Réduction du Bikeshedding : En fournissant des réponses aux questions de conception courantes, JSON:API permet aux équipes de se concentrer sur la logique métier de base de leurs applications plutôt que de débattre des détails de la conception de l'API.
- Amélioration de la productivité : Les formats standardisés signifient moins de code personnalisé pour les producteurs et les consommateurs d'API. Des bibliothèques clientes peuvent être développées pour gérer une grande partie du code passe-partout pour interagir avec n'importe quel service conforme à JSON:API.
- Amélioration de la découvrabilité et de la convivialité : Des structures de liens cohérentes et une délimitation claire des ressources et des relations facilitent la compréhension et la navigation dans les API.
- Transfert de données optimisé : Des fonctionnalités telles que les ensembles de champs clairsemés et les documents composés permettent aux clients de ne demander que les données dont ils ont besoin, minimisant ainsi la taille des charges utiles et réduisant le nombre de requêtes HTTP.
- Mise en cache plus facile : La spécification favorise l'utilisation des mécanismes de mise en cache HTTP standard.
- Indépendant du langage : Étant basé sur JSON, il est intrinsèquement indépendant du langage, ce qui facilite son adoption à travers diverses piles technologiques.
Concepts de base : les éléments constitutifs d'un document JSON:API
Au cœur de JSON:API se trouve le concept de ressources. Une ressource est un enregistrement individuel d'un type particulier, tel qu'un "article", un "utilisateur" ou un "produit". Chaque document JSON:API, qu'il s'agisse d'une requête ou d'une réponse, adhère à une structure spécifique.
La structure du document : membres de niveau supérieur
Un document JSON:API est un objet JSON qui doit contenir au moins l'un des membres de niveau supérieur suivants :
data
: Les "données principales" du document. Cela peut être :- Un seul objet ressource (par exemple, lors de la récupération d'un article spécifique).
- Un tableau d'objets ressources (par exemple, lors de la récupération d'une collection d'articles).
- Un seul objet identifiant de ressource (pour représenter une relation un-à-un).
- Un tableau d'objets identifiants de ressource (pour représenter une relation un-à-plusieurs).
null
(par exemple, lorsqu'une relation un-à-un est vide, ou une requête pour une seule ressource qui n'existe pas).- Un tableau vide
[]
(par exemple, lorsqu'une relation un-à-plusieurs est vide, ou qu'une requête pour une collection ne donne aucun résultat). errors
: Un tableau d'objets d'erreur fournissant des détails sur les erreurs de traitement. Le membredata
ne doit pas être présent sierrors
est présent.meta
: Un objet meta contenant des méta-informations non standard qui ne rentrent pas dans le reste de la spécification.
De plus, un document peut contenir ces membres de niveau supérieur :
jsonapi
: Un objet décrivant l'implémentation du serveur. Il peut inclureversion
(la version JSON:API la plus élevée prise en charge),ext
(un tableau d'URI pour les extensions appliquées) etprofile
(un tableau d'URI pour les profils appliqués).links
: Un objet liens lié aux données principales. Cela peut inclure des liens vers soi-même, des liens vers des ressources connexes et des liens de pagination.included
: Un tableau d'objets ressources qui sont liés aux données principales et/ou les uns aux autres. Ceci est utilisé pour les "documents composés" afin de réduire le nombre de requêtes HTTP en chargeant les ressources connexes.
Objets ressources : représenter vos données
Un objet ressource est la pierre angulaire de JSON:API et doit contenir :
type
: Une chaîne qui identifie le type de la ressource (par exemple,"articles"
,"users"
). Cela aide à l'espace de noms des ressources et évite les collisions d'ID entre différents types.id
: Une chaîne qui identifie de manière unique la ressource au sein de son type.
Un objet ressource peut également contenir :
attributes
: Un objet attributs contenant des données spécifiques à la ressource. Les clés de l'objetattributes
représentent les propriétés de la ressource (par exemple,"title"
,"body"
pour un article). Les relations ne doivent pas être représentées dans l'objetattributes
.relationships
: Un objet relations décrivant les connexions entre la ressource et d'autres ressources.links
: Un objet liens contenant des liens liés à la ressource, tels qu'un lienself
pointant vers l'URL canonique de la ressource.meta
: Un objet meta contenant des méta-informations non standard sur la ressource.
Exemple d'objet ressource :JSON
{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API Unveiled",
"body": "A deep dive into the specification...",
"created_at": "2025-05-15T10:00:00Z",
"updated_at": "2025-05-16T14:30:00Z"
},
"relationships": {
"author": {
"links": {
"self": "/articles/1/relationships/author",
"related": "/articles/1/author"
},
"data": { "type": "users", "id": "42" }
},
"comments": {
"links": {
"self": "/articles/1/relationships/comments",
"related": "/articles/1/comments"
},
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
}
},
"links": {
"self": "/articles/1"
}
}
Objets identifiants de ressource
Les objets identifiants de ressource sont des représentations minimales d'une ressource, contenant uniquement type
et id
. Ils sont utilisés dans les objets de relation pour établir un lien vers d'autres ressources sans intégrer l'objet ressource complet.
Exemple d'objet identifiant de ressource :JSON
{ "type": "users", "id": "42" }
Objets Liens
Les objets liens fournissent des URL pour naviguer dans l'API. Les membres de liens courants incluent :
self
: Un lien qui représente la ressource ou le document lui-même.related
: Un lien vers une ressource ou une collection connexe. Souvent utilisé dans les relations pour récupérer les données réelles connexes.- Liens de pagination :
first
,last
,prev
,next
pour naviguer dans les collections paginées.
Un lien peut être représenté comme :
- Une simple chaîne contenant l'URL.
- Un objet lien, qui doit contenir un
href
(URL de chaîne) et peut éventuellement inclurerel
(type de relation),describedby
(lien vers un document de description),title
,type
(type de média de la cible),hreflang
et un objetmeta
.
Exemple d'objet Liens (dans une relation) :JSON
"links": {
"self": "http://example.com/articles/1/relationships/author",
"related": "http://example.com/articles/1/author"
}
Objets Meta
Les objets Meta permettent l'inclusion de méta-informations non standard. Il peut s'agir de paires clé-valeur arbitraires. Par exemple, un objet meta
pourrait inclure des informations sur le droit d'auteur ou des horodatages liés aux données.
Exemple d'objet Meta :JSON
"meta": {
"copyright": "Copyright 2025 Example Corp.",
"authors": ["John Doe"]
}
Négociation de contenu : parler le bon langage
JSON:API définit son propre type de média : application/vnd.api+json
.
- En-tête
Accept
: Les clients doivent envoyer cet en-tête avec le type de médiaapplication/vnd.api+json
pour indiquer qu'ils s'attendent à une réponse conforme à JSON:API. Si un serveur ne peut pas satisfaire l'un des types de média dans l'en-têteAccept
, il doit répondre avec un statut406 Not Acceptable
. - En-tête
Content-Type
: Les clients et les serveurs doivent utiliser cet en-tête avec le type de médiaapplication/vnd.api+json
pour toutes les requêtes et réponses qui contiennent un document JSON:API dans leur corps. Si une requête spécifie unContent-Type
autre queapplication/vnd.api+json
(ou d'autres types de média enregistrés pris en charge par le serveur) et contient un corps, le serveur doit répondre avec un statut415 Unsupported Media Type
. Si une requête spécifieContent-Type: application/vnd.api+json
mais que le corps n'est pas un document JSON:API valide, le serveur doit répondre avec400 Bad Request
.
Les serveurs peuvent prendre en charge d'autres types de médias aux côtés de application/vnd.api+json
grâce à la négociation de contenu standard.
Récupération de données : récupération de ressources et de collections
JSON:API fournit des mécanismes robustes permettant aux clients de récupérer des données précisément selon leurs besoins.
Récupération de ressources individuelles
Pour récupérer une seule ressource, un client envoie une requête GET
à un point de terminaison représentant cette ressource.
Requête :
GET /articles/1
Accept : application/vnd.api+json
Réponse réussie (200 OK) :JSON
{
"links": {
"self": "/articles/1"
},
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API Rocks!"
}
// ... other attributes and relationships
}
}
Si la ressource n'existe pas, le serveur devrait renvoyer un 404 Not Found
. Si un lien de ressource connexe un-à-un est récupéré et que la relation est vide, les données principales seront null
.
Récupération de collections de ressources
Pour récupérer une collection de ressources, un client envoie une requête GET
à un point de terminaison représentant cette collection.
Requête :
GET /articles
Accept : application/vnd.api+json
Réponse réussie (200 OK) :JSON
{
"links": {
"self": "/articles",
"next": "/articles?page[offset]=10",
"last": "/articles?page[offset]=50"
},
"data": [
{
"type": "articles",
"id": "1",
"attributes": { "title": "Article 1" }
// ...
},
{
"type": "articles",
"id": "2",
"attributes": { "title": "Article 2" }
// ...
}
// ... more articles
]
}
Si la collection est vide, le membre data
sera un tableau vide []
.
Relations : connexion des ressources
Les relations sont une partie fondamentale de la plupart des modèles de données. JSON:API fournit un moyen clair de les définir et d'interagir avec elles.
Représentation des relations
Les relations sont définies dans l'objet relationships
d'une ressource. Chaque entrée de l'objet relationships
représente une relation distincte (par exemple, "auteur", "commentaires").
Un objet de relation doit contenir au moins l'un des éléments suivants :
links
: Contient des liensself
etrelated
.- Le lien
self
(URL de la relation) permet la manipulation de la relation elle-même (par exemple, ajouter/supprimer des éléments dans une relation un-à-plusieurs). Lorsqu'il est récupéré, il renvoie des objets identifiants de ressource pour les ressources connexes. - Le lien
related
(URL de la ressource connexe) permet de récupérer directement les objets de ressource connexes. data
: Contient la liaison de ressource (objets identifiants de ressource).- Pour une relation un-à-un : un seul objet identifiant de ressource ou
null
. - Pour une relation un-à-plusieurs : un tableau d'objets identifiants de ressource ou un tableau vide
[]
. meta
: Un objet meta pour les informations non standard sur la relation.
Exemple de relations "auteur" (un-à-un) et "commentaires" (un-à-plusieurs) :JSON
"relationships": {
"author": {
"links": {
"self": "/articles/1/relationships/author",
"related": "/articles/1/author"
},
"data": { "type": "users", "id": "42" }
},
"comments": {
"links": {
"self": "/articles/1/relationships/comments",
"related": "/articles/1/comments"
},
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
}
}
Récupération des relations
Les clients peuvent récupérer des informations sur une relation elle-même ou sur les ressources connexes à l'aide des liens fournis.
Récupération de la liaison de relation (lien self) :
GET /articles/1/relationships/comments
Accept : application/vnd.api+json
Cela renvoie une collection d'objets identifiants de ressource pour les commentaires liés à l'article "1".
Récupération des ressources connexes (lien related) :
GET /articles/1/comments
Accept : application/vnd.api+json
Cela renvoie une collection d'objets de ressource de commentaire complets liés à l'article "1".
Optimisation de la récupération des données
JSON:API offre plusieurs fonctionnalités pour optimiser la façon dont les données sont récupérées, minimisant la bande passante et améliorant les performances côté client.
Documents composés : réduction des requêtes HTTP avec include
Pour éviter plusieurs allers-retours vers le serveur pour récupérer les ressources connexes, JSON:API permet aux clients de demander que les ressources connexes soient incluses dans la réponse principale à l'aide du paramètre de requête include
. Le serveur chargera ensuite ces ressources dans le tableau included
de niveau supérieur.
Requête pour récupérer un article et inclure son auteur et ses commentaires :
GET /articles/1?include=author,comments
Accept : application/vnd.api+json
Réponse (200 OK) :JSON
{
"data": {
"type": "articles",
"id": "1",
"attributes": { "title": "..." },
"relationships": {
"author": {
"data": { "type": "users", "id": "42" }
},
"comments": {
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
}
}
},
"included": [
{
"type": "users",
"id": "42",
"attributes": { "name": "John Doe" }
},
{
"type": "comments",
"id": "5",
"attributes": { "body": "Great article!" }
},
{
"type": "comments",
"id": "12",
"attributes": { "body": "Very informative." }
}
]
}
- Le paramètre
include
prend une liste de chemins de relation séparés par des virgules. - Les relations imbriquées peuvent être incluses à l'aide de la notation pointée (par exemple,
include=comments.author
). - Si un point de terminaison ne prend pas en charge
include
, il doit renvoyer400 Bad Request
. - Le serveur ne doit pas inclure de ressources non demandées dans la section
included
.
Ensembles de champs clairsemés : récupération uniquement des champs nécessaires
Les clients peuvent demander que seuls des champs spécifiques (attributs et relations) soient renvoyés pour les ressources d'un type donné à l'aide du paramètre de requête fields[TYPE]
. Cela réduit la taille de la charge utile.
Requête pour récupérer des articles, mais uniquement leur titre et leur relation d'auteur :
GET /articles?fields[articles]=title,author
Accept : application/vnd.api+json
Réponse (200 OK) :JSON
{
"data": [
{
"type": "articles",
"id": "1",
"attributes": {
"title": "Article 1"
},
"relationships": {
"author": {
"data": { "type": "users", "id": "42" }
}
}
}
// ... other articles with only title and author
]
}
- L'
id
et letype
sont toujours inclus. - Si un client demande un champ qui n'existe pas, le serveur doit l'ignorer.
- Si un client ne demande que des champs qui sont des relations, le membre
attributes
peut être omis.
Tri
Les clients peuvent demander que les données principales soient triées à l'aide du paramètre de requête sort
.
Requête pour récupérer des articles triés par date de création (décroissante), puis par titre (croissant) :
GET /articles?sort=-created_at,title
Accept : application/vnd.api+json
- Un trait d'union (
-
) en tête indique l'ordre décroissant ; sinon, il est croissant. - Le serveur définit quels attributs peuvent être utilisés pour le tri. Les requêtes de tri sur des attributs non pris en charge devraient entraîner un
400 Bad Request
.
Pagination
JSON:API prend en charge diverses stratégies de pagination. La spécification définit comment les liens de pagination (first
, prev
, next
, last
) doivent apparaître dans l'objet links
de niveau supérieur. La stratégie de pagination réelle (par exemple, basée sur les pages, basée sur les décalages, basée sur les curseurs) est déterminée par le serveur à l'aide de paramètres de requête tels que page[number]
, page[size]
, page[offset]
, page[limit]
ou page[cursor]
.
Exemple de liens de pagination basés sur les pages :JSON
"links": {
"self": "/articles?page[number]=2&page[size]=10",
"first": "/articles?page[number]=1&page[size]=10",
"prev": "/articles?page[number]=1&page[size]=10",
"next": "/articles?page[number]=3&page[size]=10",
"last": "/articles?page[number]=5&page[size]=10"
}
Les clients doivent utiliser ces liens fournis plutôt que de construire leurs propres URL de pagination.
Filtrage
La spécification réserve le paramètre de requête filter
pour le filtrage des données. Cependant, elle n'impose pas de stratégie de filtrage spécifique. Les serveurs peuvent implémenter n'importe quelle stratégie, telle que filter[attribute]=value
ou un filtrage plus complexe basé sur des expressions.
Exemple (recommandé par JSON:API, mais non obligatoire) :
GET /comments?filter[post]=1 (Obtenir les commentaires pour le message avec l'ID 1)
GET /comments?filter[post]=1,2&filter[author]=12 (Obtenir les commentaires pour les messages 1 ou 2, par l'auteur 12)
Les clients doivent consulter la documentation de l'API pour comprendre ses capacités de filtrage spécifiques.
Modification des données : création, mise à jour et suppression de ressources
JSON:API définit des protocoles clairs pour les opérations de manipulation de données.
Création de ressources
Pour créer une ressource, un client envoie une requête POST
à une URL représentant une collection de ressources. Le corps de la requête doit contenir un seul objet ressource avec type
et, éventuellement, attributes
et relationships
. Le client ne doit pas fournir d'id
pour la nouvelle ressource (sauf si les ID générés par le client sont pris en charge et activés).
Requête :
POST /articles
Accept : application/vnd.api+json
Content-Type : application/vnd.api+jsonJSON
{
"data": {
"type": "articles",
"attributes": {
"title": "New Article Title",
"body": "Content of the new article."
},
"relationships": {
"author": {
"data": { "type": "users", "id": "42" }
}
}
}
}
Réponses réussies :
201 Created
: Si la ressource a été créée avec succès. La réponse doit inclure un en-têteLocation
identifiant l'URL de la ressource nouvellement créée. Le corps de la réponse devrait inclure la ressource nouvellement créée, y compris sonid
attribué par le serveur.202 Accepted
: Si la demande de création a été acceptée pour traitement, mais que le traitement n'est pas encore terminé (par exemple, pour les opérations asynchrones). La réponse peut inclure un lien pour surveiller l'état.204 No Content
: Si la ressource a été créée avec succès, mais que le serveur choisit de ne pas renvoyer la représentation de la ressource dans le corps de la réponse. L'en-têteLocation
est toujours requis.
Si une tentative est faite pour créer une ressource avec un ID généré par le client qui existe déjà, et que le serveur ne prend pas en charge la mise à jour via POST
, il doit renvoyer 409 Conflict
.
Mise à jour des ressources
Les ressources sont mises à jour à l'aide de la méthode HTTP PATCH
. La requête doit inclure l'id
de la ressource à mettre à jour. Le corps de la requête contient un objet ressource avec type
, id
et les attributes
et/ou relationships
à mettre à jour.
Requête pour mettre à jour le titre d'un article et l'une de ses relations :
PATCH /articles/1
Accept : application/vnd.api+json
Content-Type : application/vnd.api+jsonJSON
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "Updated Article Title"
},
"relationships": {
"tags": {
"data": [
{ "type": "tags", "id": "3" },
{ "type": "tags", "id": "4" }
]
}
}
}
}
Points clés pour les mises à jour :
- Mises à jour partielles : Les requêtes
PATCH
devraient être partielles. Seuls les champs présents dans la requête doivent être mis à jour. Les champs non inclus doivent rester inchangés. - Mise à jour des relations :
- Un-à-un : Fournir un objet identifiant de ressource ou
null
dans lesdata
de la relation. - Un-à-plusieurs : Fournir un tableau d'objets identifiants de ressource. Cela remplace complètement les membres de la relation existante. Pour ajouter ou supprimer des membres sans remplacer l'ensemble, des points de terminaison de relation dédiés (
/articles/1/relationships/tags
) doivent être utilisés avecPOST
(pour ajouter),DELETE
(pour supprimer) ouPATCH
(pour tout remplacer). - Le serveur ne doit pas mettre à jour les attributs ou les relations qui ne sont pas spécifiés dans la requête.
Réponses réussies :
200 OK
: Si la mise à jour a réussi et que le serveur renvoie une représentation de la ressource mise à jour.202 Accepted
: Si la demande de mise à jour a été acceptée pour traitement, mais n'est pas encore terminée.204 No Content
: Si la mise à jour a réussi, mais que le serveur choisit de ne pas renvoyer de représentation.
Si la ressource à mettre à jour n'existe pas, le serveur doit renvoyer 404 Not Found
.
Mise à jour des relations directement
JSON:API fournit des moyens spécifiques de gérer les relations sans affecter les attributs de la ressource principale.
- Mise à jour d'une relation un-à-un :
PATCH /articles/1/relationships/authorContent-Type: application/vnd.api+json
JSON
{
"data": { "type": "users", "id": "24" } // Assign new author or null to clear
}
- Mise à jour d'une relation un-à-plusieurs (remplacement complet) :
PATCH /articles/1/relationships/commentsContent-Type: application/vnd.api+json
JSON
{
"data": [
{ "type": "comments", "id": "101" },
{ "type": "comments", "id": "102" }
]
}
- Ajout à une relation un-à-plusieurs :
POST /articles/1/relationships/commentsContent-Type: application/vnd.api+json
JSON
{
"data": [
{ "type":