Existe-t-il des normes ou des meilleures pratiques pour structurer les réponses JSON à partir d'une API? Évidemment, les données de chaque application sont différentes, de sorte que cela ne me concerne pas, mais plutôt la "réponse standard", si vous voulez. Un exemple de ce que je veux dire:
Demande réussie:
{
"success": true,
"payload": {
/* Application-specific data would go here. */
}
}
Demande échouée:
{
"success": false,
"payload": {
/* Application-specific data would go here. */
},
"error": {
"code": 123,
"message": "An error occurred!"
}
}
Oui, quelques normes (bien que certaines libertés sur la définition de norme) soient apparues:
Il existe également des formats de description d'API JSON:
Réponse de réussite retour data
{
"data": {
"id": 1001,
"name": "Wing"
}
}
Retour de réponse d'erreur error
{
"error": {
"code": 404,
"message": "ID not found"
}
}
et si votre client est JS, vous pouvez utiliser if ("error" in response) {}
pour vérifier s’il ya une erreur.
Je suppose qu’un standard de facto n’a pas vraiment émergé (et peut-être jamais) . Mais peu importe, voici ce que je pense:
Demande réussie:
{
"status": "success",
"data": {
/* Application-specific data would go here. */
},
"message": null /* Or optional success message */
}
Demande échouée:
{
"status": "error",
"data": null, /* or optional error payload */
"message": "Error xyz has occurred"
}
Avantage: mêmes éléments de premier niveau dans les cas de réussite et d'erreur
Inconvénient: pas de code d'erreur, mais si vous le souhaitez, vous pouvez changer le statut en code (succès ou échec), -ou- vous pouvez ajouter un autre élément de niveau supérieur nommé "code".
En supposant que votre question concerne la conception de services Web REST et plus précisément le succès/l'erreur.
Je pense qu'il y a 3 types de design différents.
Utilisez uniquement le code d'état HTTP pour indiquer s'il y a eu une erreur et essayez de vous limiter aux erreurs standard (cela devrait normalement suffire).
Utilisez HTTP Status + json body (même s'il s'agit d'une erreur). Définissez une structure uniforme pour les erreurs (ex: code, message, raison, type, etc.) et utilisez-la pour les erreurs. Si c'est un succès, retournez simplement la réponse JSON attendue.
Oubliez le statut http (ex: toujours le statut 200), utilisez toujours json et ajoutez à la racine de la réponse un booléen responseValid et un objet d'erreur (code, message, etc.) à renseigner s'il s'agit d'une erreur. sinon, les autres champs (succès) sont renseignés.
Avantages: le client traite uniquement avec le corps de la réponse qui est une chaîne json et ignore l'état (?).
Inconvénients: le moins standard.
A vous de choisir :)
En fonction de l'API, je choisirais 2 ou 3 (je préfère 2 pour json rest apis) . Une autre chose que j'ai expérimentée dans la conception de REST Api est l'importance de la documentation pour chaque ressource (url): les paramètres , le corps, la réponse, les en-têtes, etc. + exemples.
Je vous recommanderais également d'utiliser jersey (implémentation de jax-rs) + genson (bibliothèque de liaison de données Java/json) .
MODIFIER:
La solution 2 est la plus difficile à mettre en œuvre, mais l’avantage est que vous pouvez gérer avec précision les exceptions et non seulement les erreurs commerciales, l’effort initial est plus important mais vous gagnez à long terme.
La solution 3 est facile à implémenter côté serveur et client, mais ce n’est pas très agréable, car vous devrez encapsuler les objets que vous souhaitez renvoyer dans un objet de réponse contenant également le message responseValid + error.
Je ne serai pas aussi arrogant d’affirmer qu’il s’agit d’une norme, je vais donc utiliser le formulaire «Je préfère».
Je préfère les réponses concises (lorsque je demande une liste d'articles /, je souhaite un tableau d'articles JSON).
Dans mes conceptions, j'utilise HTTP pour les rapports sur l'état, a 200 renvoie uniquement les données utiles.
400 renvoie un message indiquant ce qui n'allait pas avec la demande:
{"message" : "Missing parameter: 'param'"}
Retour 404 si le modèle/contrôleur/URI n'existe pas
S'il y a eu une erreur de traitement de mon côté, je retourne 501 avec un message:
{"message" : "Could not connect to data store."}
D'après ce que j'ai vu, de nombreux frameworks REST-ish ont tendance à être dans cette direction.
Justification :
JSON est supposé être un format payload , ce n'est pas un protocole de session. Toute l’idée des charges utiles de session-ish verbeuses vient du monde XML/SOAP et de divers choix erronés qui ont créé ces conceptions surchargées. Une fois que nous avons réalisé que tout cela constituait un gros problème, le but de REST/JSON était de le KISS et de adhérer à HTTP. Je ne pense pas qu'il y ait quelque chose de distant standard dans JSend et surtout pas avec les plus verbeux parmi eux. XHR réagira à la réponse HTTP. Si vous utilisez jQuery pour votre AJAX (comme la plupart des personnes le font), vous pouvez utiliser les rappels try
/catch
et done()
/fail()
pour capturer les erreurs. Je ne vois pas comment l’encapsulation de rapports d’état dans JSON est plus utile que cela.
Voici le format json utilisé par instagram
{
"meta": {
"error_type": "OAuthException",
"code": 400,
"error_message": "..."
}
"data": {
...
},
"pagination": {
"next_url": "...",
"next_max_id": "13872296"
}
}
Pour ce que ça vaut, je le fais différemment. Un appel réussi a juste les objets JSON. Je n'ai pas besoin d'objet JSON de niveau supérieur contenant un champ de succès indiquant true et un champ de données utiles contenant l'objet JSON. Je viens de renvoyer l'objet JSON approprié avec un 200 ou ce qui convient dans la plage 200 pour le statut HTTP dans l'en-tête.
Cependant, s'il y a une erreur (quelque chose dans la famille 400), je retourne un objet d'erreur JSON bien formé. Par exemple, si le client POST un utilisateur avec une adresse électronique et un numéro de téléphone et que l’un d’eux est mal formé (c’est-à-dire que je ne parviens pas à l’insérer dans la base de données sous-jacente), je vais renvoyer un message du type
{
"description" : "Validation Failed"
"errors" : [ {
"field" : "phoneNumber",
"message" : "Invalid phone number."
} ],
}
Les bits importants ici sont que la propriété "field" doit correspondre exactement au champ JSON qui n'a pas pu être validé. Cela permet aux clients de savoir exactement ce qui ne va pas avec leur demande. En outre, "message" est dans les paramètres régionaux de la demande. Si "emailAddress" et "phoneNumber" n'étaient pas valides, le tableau "errors" contiendrait des entrées pour les deux. Un corps de réponse JSON 409 (conflit) pourrait ressembler à ceci:
{
"description" : "Already Exists"
"errors" : [ {
"field" : "phoneNumber",
"message" : "Phone number already exists for another user."
} ],
}
Avec le code d'état HTTP et ce JSON, le client dispose de tout ce dont il a besoin pour répondre aux erreurs de manière déterministe. Il ne crée pas de nouveau standard d'erreur qui tente de remplacer les codes d'état HTTP. Notez que cela ne se produit que pour la plage de 400 erreurs. Pour tout ce qui est dans la gamme 200, je peux simplement retourner ce qui est approprié. Pour moi, il s’agit souvent d’un objet JSON, semblable à HAL, mais cela n’a aucune importance ici.
La seule chose que je pensais à ajouter était un code d'erreur numérique, soit dans les entrées du tableau "erreurs", soit à la racine de l'objet JSON lui-même. Mais jusqu'à présent, nous n'en avons pas eu besoin.
La RFC 7807: Détails du problème pour les API HTTP est actuellement la chose la plus proche d’une norme officielle.
Il n’ya pas d’accord sur les formats de réponse restants des grands géants du logiciel - Google, Facebook, Twitter, Amazon et d’autres -, bien que de nombreux liens aient été fournis dans les réponses ci-dessus, où certaines personnes ont essayé de normaliser le format de réponse.
Les besoins des API pouvant différer, il est très difficile de convaincre tout le monde et de convenir d'un format. Si des millions d'utilisateurs utilisent votre API, pourquoi changeriez-vous le format de votre réponse?
Voici mon point de vue sur le format de réponse inspiré par Google, Twitter, Amazon et quelques publications sur Internet:
https://github.com/adnan-kamili/rest-api-response-format
Fichier Swagger:
Le point essentiel de JSON est qu’il est complètement dynamique et flexible. Adaptez-le à votre guise, car il ne s'agit que d'un ensemble d'objets et de tableaux JavaScript sérialisés, enracinés dans un seul nœud.
Ce que le type de rootnode est à vous, ce qu'il contient est à vous, que vous envoyiez les métadonnées avec la réponse, à vous, que vous définissiez le type mime à application/json
ou que vous le laissiez comme text/plain
correspondait à vous (tant que vous savez comment gérer les cas Edge).
Construisez un schéma léger que vous aimez.
Personnellement, j’ai découvert que le suivi analytique, le service mp3/ogg et le service galerie d’images, la messagerie texte et les paquets réseau pour les jeux en ligne, ainsi que les blogs et les commentaires de blog all haveexigences très différentesen ce qui concerne ce qui est envoyé et ce qui est reçu et comment ils doivent être consommés.
Donc, la dernière chose que je voudrais, en faisant tout cela, est d'essayer de rendre chacun conforme au même standard standard, qui est basé sur XML2.0 ou similaire.
Cela dit, il y a beaucoup à dire sur l'utilisation de schémas qui ont du sens pourvouset qui sont bien pensés.
Lisez simplement quelques réponses de l'API, notez ce que vous aimez, critiquez ce que vous n'aimez pas, écrivez ces critiques et comprenez pourquoi elles vous frottent à l'envers, puis réfléchissez à la manière d'appliquer ce que vous avez appris à ce dont vous avez besoin.
JSON-RPC 2.0 définit un format de requête et de réponse standard et constitue une bouffée d'air frais après une utilisation des API REST.
Concernant votre deuxième exemple, la spécification JSON l’interdit :
Les données des membres et les erreurs NE DOIVENT PAS coexister dans le même document.
J'ai fait une petite recherche et trouvé que le format le plus courant pour renvoyer une erreur (exceptions) est une structure de cette forme:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
C'est le format proposé par la norme de données OASIS OASIS OData qui semble être l'option la plus standard, mais il ne semble pas que les taux d'adoption soient élevés pour aucune norme à ce stade. Ce format est conforme à la spécification JSON-RPC.
Vous pouvez trouver la bibliothèque open source complète qui l'implémente à l'adresse: Utilitaires JSON Mendocino . Cette bibliothèque prend en charge les objets JSON ainsi que les exceptions.
Les détails sont discutés dans mon article de blog sur Traitement des erreurs dans l'API JSON REST