web-dev-qa-db-fra.com

Alternatives RESTful au corps de requête DELETE

Bien que le spéc. HTTP 1.1 semble autoriser le corps du message SUPPRIMER demande, il semble que indique que les serveurs doivent l'ignorer car il n'y a pas de sémantique définie.

4.3 Corps du message

Un serveur DEVRAIT lire et transmettre un corps de message pour toute demande. si la méthode de demande n'inclut pas de sémantique définie pour un corps d'entité, le corps du message DEVRAIT être ignoré lors du traitement de la demande.

J'ai déjà examiné plusieurs discussions sur ce sujet à propos de SO et au-delà, telles que:

La plupart des discussions semblent s'accorder sur le fait que fournir un corps de message sur un DELETE peut être autorisé, mais n'est généralement pas recommandé.

De plus, j'ai remarqué une tendance dans diverses bibliothèques de clients HTTP où de plus en plus d'améliorations semblent être consignées pour que ces bibliothèques prennent en charge les corps de demande sur DELETE. La plupart des bibliothèques semblent obliger, bien que parfois avec un peu de résistance initiale.

Mon cas d'utilisation appelle l'ajout de certaines métadonnées requises sur un DELETE (par exemple, le "motif" de la suppression, ainsi que d'autres métadonnées requises pour la suppression). J'ai envisagé les options suivantes, dont aucune ne semble totalement appropriée et intégrée aux spécifications HTTP et/ou aux REST meilleures pratiques:

  • Corps du message - La spécification indique que les corps du message sur DELETE n'ont pas de valeur sémantique; pas entièrement pris en charge par les clients HTTP; pas pratique courante
  • En-têtes HTTP personnalisés - Exiger des en-têtes personnalisés est généralement par rapport aux pratiques standard ; leur utilisation est incompatible avec le reste de mon API, aucune d'entre elles n'exigeant d'en-tête personnalisé; de plus, aucune bonne réponse HTTP n'est disponible pour indiquer des valeurs d'en-tête personnalisées incorrectes (probablement une question distincte)
  • En-têtes HTTP standard - Aucun en-tête standard n'est approprié
  • Paramètres de requête - L'ajout de paramètres de requête modifie réellement l'URI de demande en cours de suppression; contre les pratiques habituelles
  • Méthode POST - (exemple: POST /resourceToDelete { deletemetadata }) POST n'est pas une option sémantique pour la suppression; POST représente en fait l'action ci-contre souhaitée (c'est-à-dire que POST crée des subordonnés de ressource; je dois toutefois supprimer la ressource).
  • Méthodes multiples - Le fractionnement de la demande DELETE en deux opérations (par exemple, PUT supprimer des métadonnées, puis DELETE) divise une opération atomique en deux, laissant potentiellement un état incohérent. Le motif de suppression (et les autres métadonnées associées) ne font pas partie de la représentation de la ressource elle-même.

Ma première préférence serait probablement d'utiliser le corps du message, suivi des en-têtes HTTP personnalisés; cependant, comme indiqué, ces approches présentent certains inconvénients.

Existe-t-il des recommandations ou des pratiques recommandées conformes aux normes REST/HTTP pour inclure de telles métadonnées requises dans les demandes DELETE? Y a-t-il d'autres alternatives que je n'ai pas envisagées?

85
shelley

Malgré certaines recommandations de ne pas utiliser le corps du message pour les demandes DELETE, cette approche peut être appropriée dans certains cas d'utilisation. C'est l'approche que nous avons finalement utilisée après avoir évalué les autres options mentionnées dans la question/réponses et après avoir collaboré avec les utilisateurs du service.

Bien que l'utilisation du corps du message ne soit pas idéale, aucune des autres options ne convenait parfaitement non plus. Le corps de la requête DELETE nous a permis d'ajouter facilement et clairement la sémantique autour des données/métadonnées supplémentaires nécessaires pour accompagner l'opération DELETE.

Je serais toujours ouvert à d'autres réflexions et discussions, mais je voulais fermer la boucle sur cette question. J'apprécie les pensées et les discussions de chacun sur ce sujet!

40
shelley

Ce que vous semblez vouloir est l’une des deux choses, qui ne sont ni une pure DELETE:

  1. Vous avez deux opérations un PUT du motif de suppression suivi d'un DELETE de la ressource. Une fois supprimé, le contenu de la ressource n'est plus accessible à personne. La "raison" ne peut pas contenir d'hyperlien vers la ressource supprimée. Ou,
  2. Vous essayez de modifier une ressource de state=active à state=deleted en utilisant la méthode DELETE. Les ressources avec l'état = supprimé sont ignorées par votre API principale mais peuvent toujours être lisibles par un administrateur ou une personne ayant accès à la base de données. Ceci est autorisé - DELETE ne doit pas effacer les données de sauvegarde d'une ressource, mais uniquement pour supprimer la ressource exposée à cet URI.

Toute opération nécessitant un corps de message sur une demande DELETE peut être décomposée en une opération plus générale, un POST pour effectuer toutes les tâches nécessaires avec le corps du message et un DELETE. Je ne vois aucune raison de casser la sémantique de HTTP.

12
Nicholas Shanks

Compte tenu de la situation que vous avez, je choisirais l'une des approches suivantes:

  • Envoyer un PUT ou un PATCH: Je déduis que l’opération de suppression est virtuelle, de par la nature même de la nécessité d’un motif de suppression. Par conséquent, je pense que la mise à jour de l'enregistrement via une opération PUT/PATCH est une approche valide, même s'il ne s'agit pas d'une opération DELETE en tant que telle.
  • tilisez les paramètres de requête: La ressource URI n'est pas modifiée. Je pense en fait que c'est aussi une approche valable. La question que vous avez liée parlait de ne pas autoriser la suppression si le paramètre de requête était manquant. Dans votre cas, j'aurais juste une raison par défaut si la raison n'est pas spécifiée dans la chaîne de requête. La ressource sera toujours resource/:id. Vous pouvez le rendre découvrable avec les en-têtes de lien sur la ressource pour chaque raison (avec une balise rel pour identifier la raison).
  • tilisez un point de terminaison distinct par raison: Utiliser une URL comme resource/:id/canceled. Cela change réellement l'URI de demande et n'est certainement pas RESTful. Encore une fois, les en-têtes de liens peuvent rendre ceci découvrable.

Rappelez-vous que REST n’est ni une loi ni un dogme. Considérez-le plutôt comme un guide. Ainsi, s’il est logique de ne pas suivre les directives relatives à votre domaine problématique, ne le faites pas. Assurez-vous simplement que votre API les consommateurs sont informés de la variance.

7
codeprogression

Je vous suggère d'inclure les métadonnées requises dans la hiérarchie d'URI elle-même. Un exemple (naïf):

Si vous devez supprimer des entrées en fonction d'une plage de dates, au lieu de transmettre la date de début et la date de fin dans un corps ou en tant que paramètres de requête, structurez l'URI de manière à transmettre les informations requises dans le cadre de l'URI.

par exemple.

DELETE /entries/range/01012012/31122012 _ - Supprimer toutes les entrées du 1er janvier 2012 au 31 décembre 2012

J'espère que cela t'aides.

0
Suresh Kumar