Je conçois un service Web RESTful à l'aide de WebApi et je me demandais quelles réponses HTTP et quels corps de réponse retourner lors de la mise à jour/création d'objets.
Par exemple, je peux utiliser la méthode POST pour envoyer du JSON au service Web, puis créer un objet. Est-il préférable de définir ensuite le statut HTTP sur created (201) ou ok (200 ) et renvoyer simplement un message tel que "Nouvel employé ajouté", ou renvoyer l'objet qui a été envoyé à l'origine?
Il en va de même pour la méthode PUT. Quel statut HTTP est préférable d'utiliser et dois-je retourner l'objet qui a été créé ou juste un message? Compte tenu du fait que l'utilisateur sait de toute façon quel objet il essaie de créer/mettre à jour.
Des pensées?
Exemple:
Ajouter un nouvel employé:
POST /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"Employee": {
"Name" : "Joe Bloggs",
"Department" : "Finance"
}
}
Mettre à jour l'employé existant:
PUT /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"Employee": {
"Id" : 1
"Name" : "Joe Bloggs",
"Department" : "IT"
}
}
Réponses:
Réponse avec objet créé/mis à jour
HTTP/1.1 201 Created
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT
{
"Employee": {
"Id" : 1
"Name" : "Joe Bloggs",
"Department" : "IT"
}
}
Réponse avec juste un message:
HTTP/1.1 200 OK
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT
{
"Message": "Employee updated"
}
Réponse avec juste le code d'état:
HTTP/1.1 204 No Content
Content-Length: 39
Date: Mon, 28 Mar 2016 14:32:39 GMT
Comme pour la plupart des choses, cela dépend. Votre compromis est la facilité d'utilisation par rapport à la taille du réseau. Il peut être très utile pour les clients de voir la ressource créée. Il peut inclure des champs remplis par le serveur, tels que l'heure de la dernière création. Comme vous semblez inclure le id
au lieu d'utiliser hateoas
, les clients voudront probablement voir l'ID de la ressource qu'ils viennent de POST
ed.
Si vous n'incluez pas la ressource créée, veuillez ne pas créer de message arbitraire. Les champs 2xx et Emplacement sont suffisamment d'informations pour que les clients soient sûrs que leur demande a été correctement traitée.
Personnellement, je toujours retourne uniquement 200 OK
.
Pour citer votre question
Compte tenu du fait que l'utilisateur sait de toute façon quel objet il essaie de créer/mettre à jour.
Pourquoi ajouter une bande passante supplémentaire (qui pourrait être payante) pour dire au client ce qu'il sait déjà?
En faisant référence au lien normes RFC , vous devez renvoyer le statut 201 (créé) si le stockage de la ressource de demande à l'aide de Post a réussi. Dans la plupart des applications, l'ID de la ressource est généré par le serveur lui-même, il est donc recommandé de renvoyer l'ID de la ressource créée. Le retour de l'ensemble de l'objet est la surcharge de la demande de publication. L'idéal est de renvoyer l'emplacement URL de la ressource nouvellement créée.
Par exemple, vous pouvez vous référer à l'exemple suivant qui enregistre l'objet employé dans la base de données et renvoie l'URL de l'objet ressource nouvellement créé en tant que réponse.
@RequestMapping(path = "/employees", method = RequestMethod.POST)
public ResponseEntity<Object> saveEmployee(@RequestBody Employee employee) {
int id = employeeService.saveEmployee(employee);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
return ResponseEntity.created(uri).build();
}
Ce point d'extrémité de repos renverra la réponse comme suit:
Statut 201 - CRÉÉ
Emplacement de l'en-tête → http: // localhost: 8080/salariés/1
@iswinky Je renvoie toujours la charge utile dans le cas des deux POST et PUT.
Dans le cas de POST vous pouvez créer l'entité avec un ID interne ou un UUID. Par conséquent, il est logique de renvoyer la charge utile.
De même, en cas de PUT, vous pouvez ignorer certains champs de l'utilisateur (valeurs immuables, par exemple), ou en cas de PATCH, les données peuvent également avoir été modifiées par d'autres utilisateurs.
Renvoyer les données telles qu'elles ont été persistantes est toujours une bonne idée et ne fait aucun mal. Si l'appelant n'a pas besoin de ces données renvoyées, il ne les traitera pas mais consommera simplement le statusCode. Sinon, ils peuvent utiliser ces données pour mettre à jour l'interface utilisateur.
Ce n'est qu'en cas de SUPPRESSION que je ne renverrais pas la charge utile et ferais soit un 200 avec un contenu de réponse, soit un 204 sans contenu de réponse.
Edit: Grâce à quelques commentaires ci-dessous, je reformule ma réponse. Je reste fidèle à la façon dont je conçois mes API et renvoie des réponses, mais je pense qu'il est logique de qualifier certaines de mes idées de conception.
a) Quand je dis renvoyer la charge utile, je voulais en fait dire renvoyer les données de la ressource, pas la même charge utile que celle fournie dans la demande. Ex: si vous envoyez une charge utile de création, je peux dans le backend créer d'autres entités telles que UUID et (peut-être) des horodatages et même des connexions (graphiques). Je renverrais tout cela dans la réponse (pas seulement la charge utile de la demande telle quelle - ce qui est inutile).
b) Je ne renverrais pas de réponses au cas où la charge utile serait très importante. J'en ai discuté dans les commentaires, mais ce que je voudrais mettre en garde, c'est que je ferais de mon mieux pour concevoir mes API ou mes ressources de telle sorte qu'il ne doive pas avoir de très grandes charges utiles. J'essaierais de décomposer les ressources en entités plus petites et gérables de sorte que chaque ressource soit définie par 15-20 attributs JSON et non plus grande.
Dans le cas où l'objet est très grand ou que l'objet parent est mis à jour, je renvoie les structures imbriquées sous forme de hrefs.
En fin de compte, j'essaierais certainement de renvoyer les données qui ont du sens pour le consommateur/l'interface utilisateur à traiter immédiatement et à effectuer une action d'API atomique plutôt que d'avoir à aller chercher 2 à 5 API supplémentaires juste pour mettre à jour l'interface utilisateur après la création/mise à jour des données.
Les API de serveur à serveur peuvent penser différemment à ce sujet. Je me concentre sur les API qui génèrent une expérience utilisateur.
Je voudrais conditionner une charge utile dans le corps de retour à un paramètre HTTP.
Le plus souvent, il est préférable de renvoyer une sorte de contenu au consommateur d'API pour éviter les allers-retours inutiles (l'une des raisons pour lesquelles GraphQL existe.)
En fait, à mesure que nos applications deviennent de plus en plus gourmandes en données et distribuées, j'essaie d'observer cette directive:
Ma directive:
Chaque fois qu'il y a un cas d'utilisation qui demande un GET immédiatement après un POST ou PUT, c'est un cas où il serait préférable de simplement renvoyer quelque chose dans la réponse POST/PUT.
Comment cela est fait et quel type de contenu à renvoyer d'un PUT ou d'un POST, qui est spécifique à l'application. Maintenant, il serait intéressant que l'application puisse paramétrer le type de "contenu" dans le corps de la réponse (voulons-nous seulement l'emplacement du nouvel objet, ou certains des champs, ou l'objet entier, etc.)
Une application pourrait définir un ensemble de paramètres qu'un POST/PUT peut recevoir pour contrôler le type de "contenu" à renvoyer dans le corps de la réponse. Ou cela pourrait coder une sorte de requête GraphQL en tant que paramètre (je peux voir que cela est utile mais aussi devenir un cauchemar de maintenance.)
De toute façon, il me semble que:
Donc, 1) faites-le, mais 2) restez simple.
Une autre option que j'ai vue est la création de points de terminaison alternatifs (par exemple,/clients pour POST/PUT qui ne renvoient rien dans le corps et/client_avec_détails pour POST/PUT à/clients, mais qui renvoient quelque chose dans le corps de la réponse.)
J'éviterais cependant cette approche. Que se passe-t-il lorsque vous devez légitimement renvoyer différents types de contenu? Un point de terminaison par type de contenu? Pas évolutif ou maintenable.