165 votes

API REST - pourquoi utiliser PUT DELETE POST GET ?

J'ai donc parcouru quelques articles sur la création d'API REST. Et certains d'entre eux suggèrent d'utiliser tous les types de requêtes HTTP : comme PUT DELETE POST GET . Nous créerons par exemple index.php et écrire API de cette manière :

$method = $_SERVER['REQUEST_METHOD'];
$request = split("/", substr(@$_SERVER['PATH_INFO'], 1));

switch ($method) {
  case 'PUT':
    ....some put action.... 
    break;
  case 'POST':
    ....some post action.... 
    break;
  case 'GET':
    ....some get action.... 
    break;
  case 'DELETE':
    ....some delete action.... 
    break;
}

Bon, d'accord, je ne connais pas grand-chose aux services web (pour l'instant). Mais ne serait-il pas plus simple d'accepter simplement JSON par l'intermédiaire d'un POST o GET (qui contiendrait le nom de la méthode et tous les paramètres) et répondrait également en JSON. Nous pouvons facilement sérialiser/désérialiser via la fonction PHP json_encode() y json_decode() et faire ce que l'on veut avec ces données sans avoir à gérer différentes méthodes de requête HTTP.

Ai-je oublié quelque chose ?

MISE À JOUR 1 :

Ok - après avoir creusé à travers plusieurs API et avoir appris beaucoup de choses sur les XML-RPC , JSON-RPC , SOAP , REST J'en suis arrivé à la conclusion que ce type d'API est judicieux. En fait, stack exchange utilise pratiquement cette approche sur ses sites et je pense que ces personnes savent ce qu'elles font. API Stack Exchange .

4 votes

Pourquoi imposer une charge utile JSON ? Et s'il n'y a pas de JSON, et qu'il s'agit d'un simple GET ?

1 votes

207voto

zzzzBov Points 62084

L'idée de RE présentation S tate T e transfert ne consiste pas à accéder aux données de la manière la plus simple possible.

Vous avez suggéré d'utiliser des requêtes postales pour accéder à JSON, ce qui est un moyen parfaitement valable d'accéder à des données et de les manipuler.

REST est une méthodologie pour significatif l'accès aux données. Lorsque vous voyez une requête en REST, vous devez immédiatement savoir ce qui se passe avec les données.

Par exemple :

GET: /cars/make/chevrolet

va probablement renvoyer une liste de voitures Chevrolet. Une bonne interface REST pourrait même incorporer des options de sortie dans la chaîne de requête, comme par exemple ?output=json o ?output=html qui permettrait à l'accesseur de décider du format dans lequel l'information doit être encodée.

Après avoir réfléchi à la manière d'intégrer raisonnablement le typage des données dans une API REST, j'ai conclu que la meilleure façon de spécifier explicitement le type de données serait d'utiliser l'extension de fichier déjà existante, telle que .js , .json , .html ou .xml . Si une extension de fichier est manquante, le format par défaut sera utilisé (par exemple JSON) ; si une extension de fichier n'est pas prise en charge, le système renverra un message d'erreur de type 501 Not Implemented code d'état .

Autre exemple :

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }

va probablement créer une nouvelle chevy malibu dans le db avec les couleurs associées. Je dis que vraisemblablement car l'interface REST n'a pas besoin d'être directement liée à la structure de la base de données. Il s'agit simplement d'une interface de masquage permettant de protéger les vraies données (comme les accesseurs et les mutateurs pour une structure de base de données).

Nous devons maintenant passer à la question de la idempotence . En général, REST met en œuvre CRUD sur HTTP. HTTP utilise GET , PUT , POST y DELETE pour les demandes.

Une implémentation très simpliste de REST pourrait utiliser le mappage CRUD suivant :

Create -> Post
Read   -> Get
Update -> Put
Delete -> Delete

Il y a un problème avec cette mise en œuvre : Post est définie comme une méthode non idempotente. Cela signifie que les appels ultérieurs de la même méthode Post se traduiront par diferente Le serveur est en état de marche. Les fonctions Get, Put et Delete sont idempotentes, ce qui signifie qu'en les appelant plusieurs fois, on obtient un état de serveur identique.

Cela signifie qu'une demande telle que :

Delete: /cars/oldest

pourrait en fait être mis en œuvre comme suit :

Post: /cars/oldest?action=delete

Considérant que

Delete: /cars/id/123456

aboutira au même état du serveur si vous l'appelez une seule fois ou si vous l'appelez 1000 fois.

Une meilleure façon de gérer la suppression de la oldest serait de demander :

Get: /cars/oldest

et utiliser le ID à partir des données obtenues pour établir une delete demande :

Delete: /cars/id/[oldest id]

Cette méthode pose un problème si un autre /cars a été ajouté entre le moment où /oldest a été demandée et lorsque le delete a été publié.

0 votes

Merci pour cette belle explication. Mais en quoi l'idempotence nous aide-t-elle dans le développement web ? Pourquoi devrions-nous nous en préoccuper ?

3 votes

@Andre c'est une combinaison de plusieurs raisons : Suivre les directives HTTP signifie que vous aurez (probablement) moins de problèmes de compatibilité ascendante lorsque les choses changent ; utiliser un formulaire html via POST avertira l'utilisateur en cas de soumissions multiples des mêmes données (ceci afin d'éviter une transaction non idempotente) ; suivre une meilleure pratique bien définie est, eh bien une meilleure pratique. Rest n'est pas défini avec une implémentation spécifique à l'esprit, ce qui vous permet de l'utiliser comme bon vous semble. Je suggérerais de tirer parti de tous les codes d'erreur et de toutes les méthodes de requête de HTTP, mais vous êtes libre de le faire comme vous l'entendez

4 votes

Le problème de cette réponse (c'est une réponse décente, mais pas complète) est qu'elle n'aborde pas la question principale qu'il a posée : Pourquoi utiliser les verbes HTTP et l'URI plutôt que des données JSON personnalisées (peut-être une sorte de syntaxe d'invocation d'API basée sur JSON). Vous pouvez créer votre syntaxe JSON personnalisée de manière à ce que ce qui se passe avec les données soit "immédiatement ... apparent". Ce que vous ne pouvez pas faire, c'est utiliser facilement des facilités intégrées et des couches de réseau au-dessus de HTTP comme vous pouvez le faire avec une API qui suit toutes les conventions REST. Non pas que ma réponse soit parfaite, bien sûr ;)

40voto

markus Points 22871

Il s'agit d'une question de sécurité et de maintenabilité.

des méthodes sûres

Dans la mesure du possible, vous devez utiliser des méthodes "sûres" (unidirectionnelles) telles que GET et HEAD afin de limiter la vulnérabilité potentielle.

méthodes idempotentes

Dans la mesure du possible, vous devez utiliser des méthodes "idempotentes" telles que GET, HEAD, PUT et DELETE, qui ne peuvent pas avoir d'effets secondaires et sont donc moins sujettes aux erreurs/plus faciles à contrôler.

Source

1 votes

Désolé, mais en quoi les méthodes PUT et DELETE sont-elles idempotentes ? Elles affectent l'état du serveur et de ses données !

27 votes

Ordinateur : L'exécution du même PUT ou du même DELETE aboutit au même état final. Cela c'est ce que signifie le terme "idempotent".

5 votes

Pour plus de clarté : une opération F est idempotente si son application unique et ses différentes applications conséquentes donnent toutes deux le même résultat. Plus précisément, F est idempotente si et seulement si F(x)=F(F(x)). Par exemple, Delete est idempotente, car lorsque vous supprimez un élément une fois, ou que vous le supprimez plusieurs fois, le résultat est le même : l'élément est supprimé une seule fois avec la première application de delete et rien ne se passe dans la deuxième ou la troisième application de delete.

29voto

Neil Whitaker Points 2886

En bref, REST met l'accent sur les noms plutôt que sur les verbes. Au fur et à mesure que votre API devient plus complexe, vous ajoutez plus de choses, plutôt que plus de commandes.

2 votes

J'ai eu un peu de mal à m'y retrouver. Cet article ( lornajane.net/posts/2013/ ) que le verbe doit provenir de la requête HTTP, de sorte que l'URI ne doit contenir que des noms, m'a permis d'y voir un peu plus clair

10voto

Merlyn Morgan-Graham Points 31815

Vous avez demandé :

Ne serait-il pas plus simple d'accepter un objet JSON par le biais d'un $_POST normal et de répondre en JSON également ?

Extrait de la Wikipedia sur REST :

Les applications RESTful maximisent l'utilisation de l'interface préexistante et bien définie et des autres capacités intégrées fournies par le protocole de réseau choisi, et minimisent l'ajout de nouvelles fonctionnalités spécifiques à l'application.

D'après le peu que j'ai vu, je pense que cela se fait généralement en maximisant l'utilisation des verbes HTTP existants et en concevant un schéma d'URL pour votre service qui soit aussi puissant et évident que possible.

Les protocoles de données personnalisés (même s'ils sont construits à partir de protocoles standard, tels que SOAP ou JSON) sont déconseillés et doivent être réduits au minimum pour se conformer au mieux à l'idéologie REST.

SOAP RPC sur HTTP, en revanche, encourage chaque concepteur d'application à définir un vocabulaire nouveau et arbitraire de noms et de verbes (par exemple getUsers(), savePurchaseOrder(...)), généralement superposé au verbe HTTP "POST". Cela ne tient pas compte de nombreuses capacités existantes du protocole HTTP, telles que l'authentification, la mise en cache et la négociation du type de contenu, et peut amener le concepteur de l'application à réinventer bon nombre de ces fonctions dans le nouveau vocabulaire.

Les objets avec lesquels vous travaillez peuvent être de n'importe quel format. L'idée est de réutiliser autant que possible HTTP pour exposer les opérations que l'utilisateur souhaite effectuer sur ces ressources (requêtes, gestion/mutation d'état, suppression).

Vous avez demandé :

Ai-je oublié quelque chose ?

Il y a beaucoup plus à savoir sur REST et sur la syntaxe des URI/les verbes HTTP eux-mêmes. Par exemple, certains verbes sont idempotents, d'autres non. Je n'ai rien vu à ce sujet dans votre question, donc je n'ai pas pris la peine d'essayer de m'y plonger. Les autres réponses et Wikipédia contiennent toutes deux de nombreuses informations utiles.

En outre, il y a beaucoup à apprendre sur les diverses technologies de réseau construites au-dessus de HTTP dont vous pouvez tirer parti si vous utilisez une API véritablement reposante. Je commencerais par l'authentification.

9voto

Pawel Cioch Points 375

En ce qui concerne l'utilisation de l'extension pour définir le type de données. J'ai remarqué que l'API MailChimp le fait, mais je ne pense pas que ce soit une bonne idée.

GET /zzz/cars.json/1

GET /zzz/cars.xml/1

Cela me semble être une bonne idée, mais je pense qu'une "ancienne" approche est meilleure - l'utilisation des en-têtes HTTP

GET /xxx/cars/1
Accept: application/json

De plus, les en-têtes HTTP sont bien meilleurs pour la communication entre types de données (si jamais quelqu'un en a besoin).

POST /zzz/cars
Content-Type: application/xml     <--- indicates we sent XML to server
Accept: application/json          <--- indicates we want get data back in JSON format

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X