Les méthodes HTTP

GET, POST, PUT, PATCH et DELETE, et lesquelles se répètent sans risque.

La méthode est le premier mot de chaque requête. Elle dit au serveur ce que vous voulez faire de la ressource à l’URL. La même URL, /api/Books/1connectez-vous pour voir, renvoie un livre avec GET, le modifie avec PUT ou PATCH, et le supprime avec DELETE. La plupart des API utilisent cinq méthodes pour presque tout, et quelques autres apparaissent de temps en temps.

C’est avec les méthodes que la différence entre un navigateur et un outil de test commence à compter. La barre d’adresse n’envoie que GET. Pour le reste, il vous faut curl, Postman, ou un bouton Envoyer comme ceux de cette page. Les exemples qui modifient des données partagées utilisent curl, pour que les boutons Envoyer de cette page ne modifient pas des enregistrements que d’autres lecteurs consultent. La leçon 6, Envoyer des requêtes avec curl et Postman, installe correctement les deux outils. Si vous n’avez pas encore curl, lisez ici les exemples curl et lancez-les après cette leçon.

Les cinq méthodes du quotidien

MéthodeFaitStatut de succès typique
GETLire une ressource ou une liste. N’envoie pas de corps.200
POSTCréer une nouvelle ressource, ou déclencher une action.201, parfois 200 ou 202
PUTRemplacer une ressource par le corps envoyé.200 ou 204
PATCHModifier certains champs d’une ressource.200 ou 204
DELETESupprimer une ressource.200 ou 204

Les points d’accès Methods de cette API acceptent chacun un verbe et décrivent ce qu’ils ont reçu. Envoyez un GET :

GET/api/methods/get?x=1

Et un POST avec un corps :

POST/api/methods/post
{"hello":"world"}

Ces points d’accès n’enregistrent rien. Pour voir ce que les méthodes font à de vraies données, il faut une ressource, et la suite de cette leçon utilise les livres.

POST crée

Créez un livre :

Terminal
curl -i -X POST https://api.testingapis.com/api/Books \
  -H "Content-Type: application/json" \
  -d '{"title":"The Pragmatic Programmer","author":"David Thomas",
       "isbn":"9780135957059","genre":"programming","publishedYear":2019,
       "pages":352,"language":"English","price":42.5,"rating":4.6,
       "available":true,"tags":["career"]}'
Cet exemple utilise des points d’accès réservés aux membres connectés.Se connecterCréer un compte gratuit
Réponse
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8

{
  "message": "Book created successfully",
  "data": {
    "id": 29,
    "title": "The Pragmatic Programmer",
    "author": "David Thomas",
    "isbn": "9780135957059",
    "genre": "programming",
    "publishedYear": 2019,
    "pages": 352,
    "language": "English",
    "price": 42.5,
    "rating": 4.6,
    "available": true,
    "tags": ["career"]
  }
}

Le serveur a répondu 201 Created, attribué l’ID 29 et renvoyé le nouvel enregistrement. Vous obtiendrez un autre ID, parce que d’autres personnes créent aussi des livres. C’est la première chose à tester sur n’importe quel POST : c’est le serveur qui choisit l’ID, et votre test doit le lire dans la réponse plutôt que le deviner.

Beaucoup d’API envoient aussi un en-tête Location avec le 201, contenant l’URL de la nouvelle ressource, comme Location: /api/Books/29connectez-vous pour voir. Celle-ci non. La norme ne l’exige pas, mais si la documentation le promettait, ce serait un bug.

Lancez maintenant le même POST une seconde fois. Vous obtenez un second livre avec un nouvel ID, identique à ce numéro près. POST ne se répète pas sans risque : chaque appel crée quelque chose de nouveau. Gardez-le en tête pour le tableau plus bas.

PUT remplace, PATCH modifie

Les deux méthodes mettent à jour un enregistrement, et on les confond sans cesse. La différence se voit dans les champs que vous omettez.

PATCH

Modifiez seulement le prix du livre 29 :

Terminal
curl -X PATCH https://api.testingapis.com/api/Books/29 \
  -H "Content-Type: application/json" \
  -d '{"price":39.99}'
Cet exemple utilise des points d’accès réservés aux membres connectés.Se connecterCréer un compte gratuit
Réponse
{
  "message": "Book patched successfully",
  "changed": ["price"],
  "ignored": [],
  "data": {
    "id": 29,
    "title": "The Pragmatic Programmer",
    "author": "David Thomas",
    "isbn": "9780135957059",
    "genre": "programming",
    "publishedYear": 2019,
    "pages": 352,
    "language": "English",
    "price": 39.99,
    "rating": 4.6,
    "available": true,
    "tags": ["career"]
  }
}

Seul le prix a changé. Tout ce que vous n’avez pas mentionné a gardé sa valeur. Cette API vous dit aussi quels champs elle a modifiés, ce qui est rare et pratique pour tester.

PUT

Envoyez maintenant un PUT avec seulement trois champs :

Terminal
curl -X PUT https://api.testingapis.com/api/Books/29 \
  -H "Content-Type: application/json" \
  -d '{"title":"The Pragmatic Programmer","author":"David Thomas","price":39.99}'
Cet exemple utilise des points d’accès réservés aux membres connectés.Se connecterCréer un compte gratuit
Réponse
{
  "message": "Book updated successfully",
  "data": {
    "id": 29,
    "title": "The Pragmatic Programmer",
    "author": "David Thomas",
    "isbn": "",
    "genre": "",
    "publishedYear": 0,
    "pages": 0,
    "language": "",
    "price": 39.99,
    "rating": 0,
    "available": false,
    "tags": []
  }
}

L’ISBN, le genre, l’année, le nombre de pages, la langue, la note et les étiquettes ont disparu. PUT veut dire "voici la nouvelle version complète de cette ressource". Tout champ que vous n’avez pas envoyé a été remplacé par une valeur vide ou nulle. L’API a fait exactement ce que PUT est censé faire, et elle a quand même effacé la majeure partie d’un enregistrement parce que le client a envoyé un corps partiel.

C’est l’un des vrais bugs les plus fréquents dans les applis. Un développeur utilise PUT pour mettre à jour un champ, n’envoie que ce champ, et tous les autres champs de l’enregistrement sont effacés sans bruit. Quand vous testez une fonction de mise à jour, envoyez un corps partiel puis faites un GET de l’enregistrement pour voir ce qui a survécu.

Certaines API gèrent cela autrement. Elles traitent un PUT avec des champs manquants comme un PATCH, ou le refusent avec un 400 parce que des champs obligatoires manquent. Cette dernière option est sans doute la plus sûre. Ce que vous testez dépend de la documentation, mais vous le testez toujours.

DELETE supprime

Supprimez le livre 29, puis essayez de le supprimer à nouveau :

Terminal
$ curl -X DELETE https://api.testingapis.com/api/Books/29
{"message":"Book deleted successfully"}          (200 OK)

$ curl -X DELETE https://api.testingapis.com/api/Books/29
{"status":404,"error":"Not Found","message":"Book with ID 29 does not exist."}   (404 Not Found)
Cet exemple utilise des points d’accès réservés aux membres connectés.Se connecterCréer un compte gratuit

Le premier appel renvoie 200 avec un message. Le second renvoie 404, parce qu’il n’y a plus rien à supprimer. Après une suppression, vérifiez aussi qu’un GET sur le même ID renvoie 404. Certains systèmes se contentent de marquer les enregistrements comme supprimés et continuent de les renvoyer, ce qui est un bug si la documentation dit le contraire.

Méthodes sûres et idempotentes

Deux propriétés de la norme HTTP décident de la façon dont les clients et les tests peuvent traiter chaque méthode.

Une méthode sûre ne change rien sur le serveur. Vous pouvez l’appeler autant de fois que vous voulez. Une méthode idempotente peut changer des choses, mais l’appeler deux fois a le même effet sur le serveur que l’appeler une fois.

MéthodeSûreIdempotente
GETOuiOui
HEADOuiOui
OPTIONSOuiOui
PUTNonOui
DELETENonOui
POSTNonNon
PATCHNonPas garanti

PUT est idempotente parce qu’envoyer deux fois le même enregistrement complet laisse le même enregistrement. DELETE est idempotente même si le second appel a reçu un 404 : la réponse était différente, mais l’état du serveur (le livre 29 n’existe pas) est le même dans les deux cas. L’idempotence porte sur l’effet, pas sur la réponse. POST n’est pas idempotente, comme vous l’avez vu quand le second POST a créé un second livre. PATCH peut aller dans un sens ou dans l’autre. Mettre le prix à 39.99 est idempotent ; un patch qui dit "ajoute 1 au stock" ne l’est pas.

Cela compte parce que les réseaux tombent en panne. Si une requête expire, le client ne sait pas si le serveur l’a reçue. Réessayer un GET ou un PUT est sans danger. Réessayer un POST peut débiter une carte deux fois. Les navigateurs, les proxys et les bibliothèques HTTP s’appuient sur ces règles pour décider s’ils réessaient d’eux-mêmes, et Timeouts, nouvelles tentatives et limites de débit montre comment les API rendent un POST réessayable sans risque grâce aux clés d’idempotence.

Pour qui teste, ces règles offrent des cas de test gratuits. Appelez un GET et vérifiez que rien n’a changé. Appelez un PUT deux fois et vérifiez que le second appel n’a rien créé ni dupliqué. Un GET qui modifie des données (comme /api/deleteUser?id=5connectez-vous pour voir, qui existe bel et bien dans certains codes) est une erreur de conception, car les robots d’indexation, les aperçus de liens et le préchargement du navigateur envoient tous des requêtes GET sans demander.

HEAD et OPTIONS

HEAD est un GET sans le corps. Le serveur envoie le même statut et les mêmes en-têtes que pour un GET, et s’arrête là. Les clients l’utilisent pour vérifier si quelque chose existe ou quelle taille fait un fichier sans le télécharger.

curl -I https://api.testingapis.com/api/methods/head
HTTP/1.1 200 OK
x-message: HEAD request received. Responses to HEAD carry headers only.
x-method: HEAD

OPTIONS demande ce qui est permis sur une URL. Les navigateurs l’envoient automatiquement avant certaines requêtes cross-origin (un "preflight"), c’est pourquoi elle apparaît dans les journaux réseau même quand aucun code ne l’appelle. Vous la testerez rarement directement, sauf si vous travaillez sur la configuration CORS.

OPTIONS/api/methods/options

Utiliser la mauvaise méthode

/api/methods/get n’accepte que GET. Envoyez-lui un POST avec curl -i -X POST https://api.testingapis.com/api/methods/get :

Réponse
HTTP/1.1 405 Method Not Allowed
Content-Length: 0
allow: GET

405 Method Not Allowed signifie que l’URL existe mais n’accepte pas cette méthode. L’en-tête allow liste celles qu’elle accepte. Un POST sur un livre précis, qui n’a pas de sens puisqu’on crée les livres sur /api/Booksconnectez-vous pour voir, reçoit le même traitement :

curl -i -X POST https://api.testingapis.com/api/Books/1
HTTP/1.1 405 Method Not Allowed
Content-Length: 0
allow: DELETE, GET, HEAD, PATCH, PUT
Cet exemple utilise des points d’accès réservés aux membres connectés.Se connecterCréer un compte gratuit

Envoyer chaque méthode à chaque point d’accès est un test peu coûteux qui trouve de vrais problèmes. Vous cherchez les méthodes qui devraient être refusées et ne le sont pas (un DELETE qui fonctionne sur un point d’accès censé être en lecture seule), et les 500 ou 404 là où un 405 s’impose. Notez que cette API renvoie le 405 avec un corps vide, alors que ses autres erreurs sont en JSON. Les clients qui attendent un corps d’erreur JSON sur chaque 4xx trébucheront dessus.

Exercice

Faites ceci avec curl (ou revenez-y après la leçon sur curl).

  • Créez un livre avec POST. Notez son ID.
  • Modifiez son titre avec PATCH. Faites un GET et confirmez que seul le titre a changé.
  • Faites un PUT avec un corps qui contient tous les champs sauf tags. Qu’est-il arrivé aux étiquettes ?
  • Envoyez à nouveau le même PUT. Quelque chose a-t-il changé la seconde fois ?
  • Supprimez-le avec DELETE, faites un GET, puis un nouveau DELETE. Notez les trois codes de statut.
  • Envoyez un DELETE à /api/Booksconnectez-vous pour voir (sans ID). Avant de le lancer, prédisez le code de statut. Puis regardez l’en-tête allow.

S’entraîner et aller plus loin