HTTP : les cas d’utilisation

À travers différents cas d’utilisation, nous allons clarifier le rôle des méthodes HTTP et exploiter différents codes statut.

Obtenir la représentation d’une ressource

Lorsqu’un client désire obtenir la représentation d’une ressource auprès d’un serveur, il utilise toujours la méthode GET. En cas du succès, le serveur doit répondre le code 200 ainsi que la représentation de la ressource.

La requête

GET /web+service HTTP/1.1
Host: www.dictionary.info

La réponse du serveur en cas de succès

HTTP/1.1 200 OK
Content-type: text/plain; charset=utf-8
Content-language: en
Content-length: 226

A Web Service is a method of communication between two electronic devices over a network.
It is a software function provided at a network address over the web with the service always on
as in the concept of utility computing.

Obtenir uniquement les meta-informations d’une ressource

Un client peut souhaiter obtenir des meta-informations sur une ressource. Par exemple, il souhaite vérifier qu’une ressource existe sans nécessairement obtenir sa représentation. Dans ce cas, il doit utiliser la méthode HEAD. Cette méthode se comporte comme la méthode GET mais sans retourner le corps du message

La requête

HEAD /web+service HTTP/1.1
Host: www.dictionary.info

La réponse du serveur en cas de succès

HTTP/1.1 200 OK
Content-type: text/plain; charset=utf-8
Content-language: en
Content-length: 226

Pour une requête HEAD, le serveur peut ou non retourner les informations relatives à la taille du message (l’en-tête Content-length).

Créer une ressource dont on connait l’URI

Lorsqu’un client veut créer une ressource sur le serveur, il faut distinguer le cas où le client connaît l’URI finale de la ressource du cas où c’est au serveur de déterminer l’URI finale. Dans le cas où l’utilisateur connaît l’URI, la méthode sera toujours un PUT. En cas de succès, le serveur devrait répondre le code 201.

La requête

PUT /individu/David+Gayerie HTTP/1.1
Host: exemple.fr
Content-type: application/json; charset=utf-8
Content-length: 91

{"name" : "Gayerie",
 "firstname" : "David",
 "email" : "david.gayerie@yopmail.com"}

La réponse du serveur en cas de succès

HTTP/1.1 201 Created
Content-length: 0

Dans l’exemple ci-dessus, le client souhaite créer une nouvelle ressource identifiée par l’URI http://exemple.fr/individu/David+Gayerie.

La plupart du temps, la ressource créée par le serveur n’est pas strictement conforme à la représentation transmise par le client. Le serveur peut, par exemple, ajouter des données telles que la date de création ou la version. Dans la sémantique HTTP, le serveur est libre d’ignorer tout ou partie des informations transmises par le client et de rajouter les informations qui lui semble nécessaires. Ainsi un client ne peut jamais être sûr que la représentation transmise au serveur correspondra bien à celle obtenue par en réponse à une requête GET sur l’URI de la ressource. Pour éviter au client de faire une requête GET supplémentaire, on admet qu’une requête PUT peut retourner une représentation de la ressource qui vient d’être créée.

Créer une ressource dont on ne connait pas l’URI

Dans le cas où l’utilisateur ne connaît pas l’URI finale de la ressource, la méthode sera toujours un POST. En cas de succès, le serveur devrait répondre le code 201 et un en-tête Location donnant au client l’URI de la nouvelle ressource.

La requête

POST /individu/ HTTP/1.1
Host: exemple.fr
Content-type: application/x-www-form-urlencoded; charset=utf-8
Content-length: 65

name=Gayerie&firstname=David&email=david.gayerie@yopmail.com

La réponse du serveur en cas de succès

HTTP/1.1 201 Created
Location: http://exemple.fr/individu/000001
Content-length: 0

Dans l’exemple ci-dessus, le client souhaite créer une ressource et le serveur décide d’identifier cette nouvelle ressource par l’URI http://exemple.fr/individu/000001. Dans ce cas, la méthode POST a la sémantique d’un ajout d’une ressource à un ensemble (celui des individus).

La plupart du temps, la ressource créée par le serveur n’est pas strictement conforme à la représentation transmise par le client. Le serveur peut, par exemple, ajouter des données telles que la date de création ou la version. Dans la sémantique HTTP, le serveur est libre d’ignorer tout ou partie des informations transmises par le client et de rajouter les informations qui lui semble nécessaires. Ainsi un client ne peut jamais être sûr que la représentation transmise au serveur correspondra bien à celle obtenue par en réponse à une requête GET sur l’URI fournie par l’en-tête Location. Pour éviter au client de faire une requête GET supplémentaire, on admet qu’une requête POST peut retourner une représentation de la ressource qui vient d’être créée.

Supprimer l’accès à une ressource

La requête

DELETE /individu/000001 HTTP/1.1
Host: exemple.fr

La réponse du serveur en cas de succès

HTTP/1.1 204 No content

Mettre à jour une ressource

La mise à jour complète d’une ressource existante se fait grâce à la méthode PUT.

La requête

PUT /individu/David+Gayerie HTTP/1.1
Host: exemple.fr
Content-type: application/json; charset=utf-8
Content-length: 91

{"name" : "Gayerie",
 "firstname" : "David",
 "email" : "david.gayerie@yopmail.com"}

La réponse du serveur en cas de succès

HTTP/1.1 204 No content

La requête de l’exemple ci-dessus est strictement identique à celle de la section *Créer une ressource dont on connaît l’URI*. Seule la réponse du serveur fait la différence : 204 signifie que la requête a été acceptée mais sans préciser une création (cela signifie que l’opération a été une mise à jour). Le client ne sait pas a priori s’il demande une création ou une modification. Cela correspond parfaitement à la caractéristique d’idempotence de la méthode PUT : la requête peut donc être répétée 1 à N fois et produira la même résultat sur le serveur.

Nous verrons avec les requêtes conditionnelles que le client peut, s’il le désire, s’assurer que sa requête est bien une requête de mise à jour.

Mettre à jour partiellement une ressource

La méthode PATCH a été introduite par la RFC 5789 afin de fournir une méthode pour la mise à jour partielle d’une ressource.

La requête

PATCH /individu/David+Gayerie HTTP/1.1
Host: exemple.fr
Content-type: application/json-patch+json; charset=utf-8
Content-length: 53

{"op" : "add",
 "path" : "/taille",
 "value" : 174}

La réponse du serveur en cas de succès

HTTP/1.1 204 No content

La difficulté de l’utilisation de la méthode PATCH vient de la nécessité pour le serveur et le client de partager un format de représentation permettant de décrire les modifications à apporter. L’exemple précédent utilise le format JSON patch proposé par la RFC 6902. Le client demande au serveur d’ajouter l’attribut « taille » à la ressource avec pour valeur le nombre 174. JSON patch a précisément été créé pour être utilisé conjointement avec la méthode PATCH.

La méthode PATCH est relativement peu implémentée et utilisée. Même si la mise à jour partielle semble une opération élémentaire sur des données, des utilisations judicieuses de POST et PUT suffisent généralement à produire une API Web efficace.

Exécuter un processus de traitement

Il est parfois utile de demander à un serveur de traiter de l’information pour obtenir un résultat. Le résultat n’est pas une ressource dont le serveur serait le dépositaire. Il s’agit juste d’une information qui est calculée mais non conservée par le serveur. Dans ce cas, le client doit utiliser la méthode POST.

La requête

POST /calculatrice HTTP/1.1
Host: www.monserveur.fr
Content-Type: application/x-www-form-urlencoded
Content-Length: 40

operande=2&operande=3&operation=addition

La réponse du serveur en cas de succès

HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 1

5

Dans l’exemple précédent, la réponse ne contient ni l’en-tête Location ni l’en-tête Content-location. Cela signifie que la réponse à la requête POST n’est associée à aucune ressource du serveur. Donc, il s’agit bien d’un simple résultat de traitement.

Connaître les méthodes autorisées

Si un client tente d’appliquer une méthode HTTP interdite sur une ressource, le serveur répond généralement par le code statut 405 (Method not allowed).

Afin de permettre au client d’être informé de la liste des méthodes autorisées pour une URI, le serveur peut ajouter l’en-tête Allow dans sa réponse. Cet en-tête liste les méthodes autorisées séparées par une virgule.

Le client peut également émettre une requête avec la méthode OPTIONS pour obtenir cet en-tête Allow :

La requête

OPTIONS /individu/David+Gayerie HTTP/1.1
Host: exemple.fr

La réponse du serveur en cas de succès

HTTP/1.1 200 OK
Content-length: 31
Content-type: text/plain
Allow: GET, HEAD, DELETE, PUT, OPTIONS

GET, HEAD, DELETE, PUT, OPTIONS

La méthode OPTIONS est souvent désactivée sur les serveurs Web pour des raisons de sécurité. Le comble est donc que la plupart des requêtes OPTIONS aboutissent à un code d’erreur 405 (method not allowed).

Traitement asynchrone d’une requête

Parfois, le serveur ne peut pas traiter complètement une requête dans un temps acceptable. Dans ce cas, il peut retourner le code 202 qui signifie qu’il a bien compris et accepté la requête mais qu’il ne l’a pas encore traitée.

La requête

DELETE /individu/000001 HTTP/1.1
Host: exemple.fr

La réponse du serveur lorsque la requête est traitée en asynchrone

HTTP/1.1 202 Accepted
Location: http://exemple.fr/jobs/1948321
Content-type: text/plain
Content-length: 53

Traitement http://exemple.fr/jobs/1948321 en cours...

Dans l’exemple ci-dessus, la requête a conduit à la création d’une ressource temporaire représentant le traitement en cours. L’en-tête Location donne l’URI où le client pourra se rendre pour consulter l’état du traitement.

Les redirections

Les redirections correspondent aux codes statut de la famille 3XX. Elles permettent au serveur de réorienter le client vers une nouvelle URI. À la réception d’un code de redirection, le client doit comprendre que pour terminer sa requête, il doit exécuter une nouvelle requête vers une URI fournie dans la réponse par le serveur grâce à l’en-tête Location.

Évolution du service

Le cas le plus simple d’utilisation des redirections est celui où le serveur évolue dans le temps. Des évolutions peuvent entraîner une modification des URI. Plutôt que de retourner simplement une erreur, le serveur propose une redirection pour assurer une continuité du service. Dans ce cas, le serveur peut retourner un code statut 301 (Moved Permanently) avec un en-tête Location donnant la nouvelle URI.

Le serveur signale un changement de l’URI du service

HTTP/1.1 301 Moved Permanently
Location: http://mon.nouveau.serveur.fr/ma/ressource/cible

URI volatile et canonicalisation d’URI

Nous verrons que dans une architecture REST, une ressource ne doit être identifié que par une seule URI. Pourtant il existe de nombreux cas d’utilisation où l’on désire rendre accessible la représentation d’une ressource à partir de différentes URI. Par exemple, imaginons une suite de news, chaque article dispose de sa propre URI mais on peut souhaiter exposer une URI permettant d’accéder au dernier article publié. Cette URI désignera forcément dans le temps des ressources différentes. Elle est volatile. Dans ce cas, le serveur peut retourner pour cette URI le code statut 307 (Temporary redirect) qui demande au client de refaire la même requête vers l’URI donnée en réponse par l’en-tête Location.

Requête sur une URI volatile

GET /articles/latest HTTP/1.1
Host: www.mynews.fr

Redirection du serveur…

HTTP/1.1 307 Temporary redirect
Location: http://www.mynews.fr/articles/les+nouvelles+du+monde.html

La redirection est coûteuse car elle oblige le client à émettre une nouvelle requête vers le serveur. Si le serveur peut répondre directement, il peut renvoyer une code 2XX avec le message attendu et ajouter l’en-tête de réponse Content-location qui indique au client la véritable URI pour cette ressource (appelée URI canonique).

… ou canonicalisation grâce à l’en-tête Content-location

HTTP/1.1 200 OK
Content-Location: http://www.mynews.fr/articles/les+nouvelles+du+monde.html
Cache-control: no-store
Content-type: text/plain
Content-length: 35

Il n'y pas de nouvelle du monde :(

Séparer le traitement de la requête de son résultat

Nous avons vu précédemment qu’il est possible de réaliser des requêtes asynchrones en HTTP. Mais il existe d’autres cas pour lesquels le serveur ne souhaite pas retourner directement de réponse au client.

Dans la navigation Web, un cas répandu est le POST/Redirect/GET. La méthode POST n’est pas idempotente. Lorsqu’un utilisateur remonte dans son historique de navigation jusqu’à une requête POST, le navigateur n’a pas d’autre choix que de demander à l’utilisateur s’il désire soumettre à nouveau cette requête. Il est donc souhaitable de faire disparaître les méthodes non idempotentes de l’historique de navigation. Or un navigateur Web ne conserve pas l’historique d’une requête dont la réponse est une redirection (ou plus exactement, il lui substitue la requête de redirection). Il est donc possible de supprimer les requêtes POST de l’historique de navigation en s’assurant que les réponses sont toujours des redirections avec une méthode GET vers une page de résultat : il s’agit du modèle du POST/Redirect/GET. Pour cela, le développeur de site Web doit s’assurer que le code statut en réponse à une méthode POST est un code 303 (See Other). L’en-tête de réponse Location indique à quelle URI le client doit soumettre la requête GET de redirection.

Une requête POST

POST /individu/ HTTP/1.1
Host: exemple.fr
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 65

name=Gayerie&firstname=David&email=david.gayerie@yopmail.com

La réponse du serveur avec une redirection

HTTP/1.1 303 See Other
Location: http://exemple.fr/individu/000001

302, 303 et 307 : quelles différences ? HTTP définit trois codes statut de redirection assez proches : 302 (Found), 303 (See Other) et 307 (Temporary Redirect). Il existe cependant une différence majeure entre ces trois codes qui correspond à des cas d’utilisation différents.

302
Il s’agit d’un code hérité de HTTP 1.0. Sa signification est ambiguë. C’est d’ailleurs pour cela que les codes 303 et 307 ont fait leur apparition dans HTTP 1.1. Pour une application serveur, il est déconseillé de s’en servir. Pour une application cliente, il est conseillé de le traiter comme un code statut 303
303
Ce code stipule que la requête a été traitée par le serveur. Cependant le client ne peut connaître le résultat que s’il soumet une requête GET à l’URI fournie en réponse dans l’en-tête Location.
307
Ce code stipule que la requête n’a pas été traitée par le serveur. Le client doit donc soumettre à nouveau la même requête quelle que soit la méthode à l’URI fournie en réponse dans l’en-tête Location.

Exercice

utilisation d’une API Web

Vous devez utiliser l’API Web du site http://rest-bookmarks.herokuapp.com pour réaliser les opérations suivantes :

  • Créer une nouvelle ressource bookmark (montrez qu’il est possible d’utiliser deux méthodes HTTP différentes)
  • Obtenir la représentation de la ressource bookmark que vous avez créée
  • Mettre à jour la ressource bookmark que vous avez créée
  • Supprimer la ressource bookmark que vous avez créée
  • Mettre à jour la dernière ressource bookmark ajoutée par n’importe quel client

Utilisez des commandes cURL pour réaliser les actions ci-dessus.

Pendant vos tests, il est très fortement conseillé d’utiliser l’option -v de cURL afin de bien visualiser la requête que vous envoyez mais également le code statut et les en-têtes retournés par le serveur.