Maison >Problème commun >Sémantique REST et HTTP
Roy Fielding a créé REST comme thèse de doctorat.
Après l'avoir lu, je le résumerais à trois éléments de base :
Un document qui décrit les statistiques d'objet
Un mécanisme de transport pour transmettre l'état de l'objet dans les deux sens entre les systèmes
Un ensemble d'opérations à effectuer sur l'état
Alors que Roy se concentrait uniquement sur HTTP, je ne vois pas pourquoi un autre transport ne pourrait pas être utilisé. Voici quelques exemples :
Montez un partage WebDAV (WebDAV est une extension HTTP, il utilise donc toujours HTTP). Copiez une feuille de calcul (.xls, .xlsx, .csv, .ods) dans le dossier monté, où chaque ligne correspond à l'état nouveau/mis à jour. L'acte de copier dans le partage indique l'opération d'insertion, le nom du fichier indique le type de données et les colonnes sont les champs. Le serveur répond avec (nom du document)-status.(suffixe du document), qui fournit une clé pour chaque ligne, un statut et éventuellement un message d'erreur. Dans ce cas, cela n'a pas vraiment de sens de demander des données.
Utilisez gRPC. L'objet transmis est le document, HTTP est le transport et le nom de la méthode distante est l'opération. Les données peuvent être à la fois fournies et demandées.
Utilisez FTP. Semblable à WebDAV, il est basé sur des fichiers. La commande PUT est une opération d'insertion et la commande GET est une requête. GET fournit uniquement un nom de fichier. Il fournit donc généralement toutes les données du type spécifié. Il est possible d'autoriser des noms de fichiers spéciaux qui indiquent un filtre codé en dur pour OBTENIR un sous-ensemble de données.
Chaque fois que je vois des implémentations REST dans la nature, elles ne suivent souvent pas le protocole HTTP de base. sémantique, et je n'ai jamais vu d'explication donnée à cela, juste un tas d'opinions diverses. Aucun de ceux que j'ai trouvés ne faisait référence à la RFC. La plupart semblent comprendre que :
POST = Créer
PUT = Mettre à jour l'intégralité du document
PATCH = Mettre à jour une partie d'un document
GET = Récupérer l'intégralité du document
Ceci est contraire à ce que HTTP déclare concernant POST et PUT :
PUT est "créer" ou "mettre à jour". GET renvoie généralement le dernier PUT. Si PUT crée, il DOIT renvoyer 201 Créé. Si PUT des mises à jour, il DOIT renvoyer 200 OK ou 204 Aucun contenu. La RFC suggère que le contenu pour 200 OK d'un PUT devrait être le statut de l'action. Je pense qu'il serait acceptable, dans le cas de SQL, de renvoyer la nouvelle ligne à partir d'une instruction select. Cela présente l'avantage que toutes les colonnes générées sont renvoyées à l'appelant sans avoir à effectuer un GET distinct.
POST traite une ressource selon sa propre sémantique. Les RFC plus anciennes indiquaient que POST était destiné aux subordonnés d'une ressource. Toutes les versions donnent l'exemple de la publication d'un article sur une liste de diffusion ; toutes les versions indiquent que si une ressource est créée, 201 Created DOIT être renvoyée.
Je dirais qu'en réalité, ce que POST signifie réellement :
Toute manipulation de données, à l'exception de la création, de la mise à jour complète/partielle ou de la suppression
Toute opération qui n'est pas une manipulation de données, telle que :
Effectuer une recherche en texte intégral des lignes qui correspondent à une expression.
Générez un objet SIG à afficher sur une carte.
Le mot DOIT signifie votre l'implémentation n'est conforme à HTTP que si vous faites ce qui est indiqué. Utiliser PUT uniquement pour les mises à jour ne cassera évidemment rien, simplement parce qu'il n'est pas conforme à la RFC. Si vous fournissez des clients qui gèrent tous les détails de l'envoi/réception de données, alors les verbes utilisés n'auront pas beaucoup d'importance pour l'utilisateur du client.
Je suis le genre de gars qui veut une raison pour ne suit pas la RFC. Je n'ai jamais compris l'importance de séparer la création de la mise à jour dans les API REST, pas plus que dans les applications Web. Pensez aux applications de téléphone portable comme les rendez-vous de l'agenda, les notes, les contacts, etc :
"Créer" clique sur l'icône plus, qui affiche un nouveau formulaire avec des valeurs vides ou par défaut.
"Mettre à jour" consiste à sélectionner un objet et à appuyer sur l'icône en forme de crayon, qui affiche un formulaire de saisie avec les valeurs actuelles.
Une fois le formulaire de saisie affiché, il fonctionne exactement de la même manière en termes de validations de champ.
Alors pourquoi les API REST et les frontaux Web devraient-ils être différents des applications pour téléphones portables ? S'il est utile pour les utilisateurs de téléphones d'obtenir le même formulaire de saisie de données pour "créer" et "mettre à jour", ne serait-il pas tout aussi utile pour les utilisateurs de l'API et du Web ?
Si vous décidez d'utiliser PUT comme "créer" ou "mettre à jour" et que vous utilisez SQL comme magasin, la plupart des fournisseurs ont une sorte de requête upsert. Malheureusement, cela ne permet pas de décider quand renvoyer 200 OK ou 201 Créé. Vous devrez examiner les informations fournies par votre pilote lors de l'exécution d'une requête DML pour trouver un moyen de distinguer l'insertion de la mise à jour pour un upsert ou utiliser une autre stratégie de requête.
Un exemple simple serait d'effectuer un ensemble de mises à jour... où colonne pk = valeur pk. Si une ligne a été affectée, alors cette ligne existe et a été mise à jour ; sinon, la ligne n'existe pas et une insertion est nécessaire. Sur Postgres, vous pouvez profiter de la clause RETURNING , qui peut en fait renvoyer n'importe quoi, pas seulement des données de ligne, comme suit :
SQL VALUES (...) ON CONFLICT(
INSERT INTO <table> VALUES (...) ON CONFLICT(<pk column>) DO UPDATE SET (...) RETURNING (SELECT COUNT(<pk column>) FROM <table> WHERE <pk column> = <pk value>) exists
Le génie de ceci est que :
La sous-sélection dans la clause RETURNING est exécutée en premier, elle détermine donc si la ligne existe avant l'exécution de la requête INSERT ON CONFLICT UPDATE. Le résultat de la requête est une colonne nommée "exists", qui vaut 1 si la ligne existait avant la requête. exécuté, 0 si ce n'est pas le cas.
La clause RETURNING peut également renvoyer les colonnes de la ligne, y compris tout ce qui a été généré et qui n'a pas été fourni.
Vous n'avez qu'à déterminer une seule fois comment gérer si une insertion ou une mise à jour est nécessaire et faire une abstraction simple que tous vos PUT peuvent appeler et qui gère 200 OK ou 201 Créé.
Un avantage intéressant de l'utilisation PUT comme prévu, c'est que dès que vous voyez un POST vous savez avec certitude qu'il ne s'agit pas d'une récupération ou d'une persistance, et à l'inverse, vous savez qu'il faut rechercher POST pour trouver le code de toute opération qui n'est pas une récupération ou une persistance.
Je pense que les avantages de l'utilisation de PUT et POST tels que décrits dans la RFC l'emportent sur les raisons pour lesquelles les gens les utilisent d'une manière qui n'est pas conforme à la RFC.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!