Commencer avec le repos
Présentation REST
REST signifie REpresentational State Transfer et a été inventé par Roy Fielding dans sa thèse de doctorat [Architectural Styles and the Design of Network-based Software Architectures][1 ]. Il y identifie des principes architecturaux spécifiques tels que :
-
Ressources adressables : l’abstraction clé des informations et des données dans REST est une ressource et chaque ressource doit être adressable via un URI.
-
Une interface uniforme et contrainte : utilisation d’un petit ensemble de méthodes bien définies pour manipuler nos ressources.
-
Orienté représentation : une ressource référencée par un URI peut avoir différents formats et différentes plates-formes ont besoin de différents formats, par exemple les navigateurs ont besoin de HTML, JavaScript a besoin de JSON et les applications Java peuvent avoir besoin de XML, JSON, CSV, texte, etc. Nous interagissons donc avec services utilisant la représentation de ce service.
-
Communiquez sans état : les applications sans état sont plus faciles à mettre à l’échelle.
-
L’hypermédia comme moteur de l’état des applications : laissez nos formats de données piloter les transitions d’état dans nos applications.
L’ensemble de ces principes architecturaux est appelé REST. Les concepts de REST sont inspirés de celui de HTTP. Roy Fielding qui nous a donné REST est également l’un des auteurs des spécifications HTTP.
[Web Services] [2] et RESTful Web Services sont des services qui sont exposés à Internet pour un accès programmatique. Ce sont des API en ligne que nous pouvons appeler depuis notre code. Il existe deux types de [« gros » services Web][3] de services Web SOAP et REST.
[Services Web RESTful][4] : les services Web qui sont écrits en appliquant les concepts architecturaux REST sont appelés services Web RESTful, qui se concentrent sur les ressources système et sur la façon dont l’état d’une ressource peut être transféré via le protocole HTTP à différents clients.
Ce document est uniquement axé sur les services Web RESTful, nous n’entrerons donc pas dans les détails de SOAP WS.
Il n’y a pas de règles strictes lors de la conception de services Web RESTful comme
- Aucune norme de protocole
- Aucune norme de canal de communication
- Aucune norme de définition de service
Mais SOAP a des règles strictes pour tout cela. Tous les services Web SOAP suivent la spécification SOAP qui dicte ce que devraient être tous les services Web SOAP. Cette spécification est développée et gérée par un comité et si SOAP WS ne suit même pas une seule règle, alors par définition ce n’est pas SOAP.
Concepts de services Web RESTful
Il existe quelques directives à prendre en compte lors de la conception/du développement d’une API RESTful :
- Emplacements/URI basés sur les ressources
- Utilisation correcte des méthodes HTTP
- HATEOAS (Hypermedia comme moteur d’état d’application)
L’approche principale lors du développement d’API RESTful devrait être de rendre l’API “aussi RESTful que possible”.
[1] : http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm [2] : https://docs.oracle.com/javaee/6/tutorial/doc/gijvh.html [3] : https://docs.oracle.com/javaee/6/tutorial/doc/giqsx.html [4] : https://docs.oracle.com/javaee/6/tutorial/doc/giqsx.html#gkcaw
REST sur HTTP
REST est une architecture indépendante du protocole proposée par Roy Fielding dans sa thèse (le chapitre 5 étant la présentation de REST), qui généralise le concept éprouvé des navigateurs Web en tant que clients afin pour dissocier les clients d’un système distribué des serveurs.
Pour qu’un service ou une API soit RESTful, il doit respecter des contraintes données telles que :
- Serveur client
- Apatride
- Cacheable
- Système en couches
- Interface uniforme
- Resources identification
- Resources representation
- Self-descriptive messages
- Hypermedia
Outre les contraintes mentionnées dans la thèse de Fielding, dans son article de blog REST APIs must be hypertext-driven , Fielding a précisé que ** le simple fait d’invoquer un service via HTTP ne le rend pas RESTful **. Un service doit donc également respecter d’autres règles qui sont résumées comme suit :
-
L’API doit respecter et ne pas violer le protocole sous-jacent. Bien que REST soit utilisé via HTTP la plupart du temps, il n’est pas limité à ce protocole.
-
Fort accent sur les ressources et leur présentation via les types de médias.
-
Les clients ne doivent pas avoir de connaissances initiales ou d’hypothèses sur les ressources disponibles ou leur état renvoyé ([ressource “typée”] (http://soabits.blogspot.co.at/2012/04/restful-resources-are-not-typed .html)) dans une API mais apprenez-les à la volée via des requêtes émises et des réponses analysées. Cela donne au serveur la possibilité de se déplacer ou de renommer facilement des ressources sans interrompre une implémentation client.
Modèle de maturité de Richardson
Le Richardson Maturity Model est un moyen d’appliquer des contraintes REST sur HTTP afin d’obtenir des services Web RESTful.
Leonard Richardson a divisé les applications en ces 4 couches :
- Niveau 0 : utilisation de HTTP pour le transport
- Niveau 1 : utilisation d’URL pour identifier les ressources
- Niveau 2 : utilisation des verbes HTTP et des statuts pour les interactions
- Niveau 3 : utilisation de HATEOAS
Comme l’accent est mis sur la représentation de l’état d’une ressource, la prise en charge de plusieurs représentations pour la même ressource est encouragée. Une représentation pourrait donc présenter une vue d’ensemble de l’état de la ressource tandis qu’une autre renvoie les détails complets de la même ressource.
Notez également que compte tenu des contraintes Fielding, une API n’est effectivement RESTful qu’une fois le 3e niveau du RMM implémenté.
Requêtes et réponses HTTP
Une requête HTTP est :
- Un verbe (ou méthode), la plupart du temps parmi GET, [POST](https://tools.ietf .org/html/rfc7231#section-4.3.3), METTRE, [SUPPRIMER](https://tools.ietf .org/html/rfc7231#section-4.3.5) ou PATCH
- Une URL
- En-têtes (paires clé-valeur)
- Eventuellement un corps (c’est-à-dire charge utile, données)
Une réponse HTTP est :
- Un statut, la plupart du temps parmi 2xx (succès), [4xx (erreur client)](https://tools. ietf.org/html/rfc7231#section-6.5) ou 5xx (erreur de serveur)
- En-têtes (paires clé-valeur)
- Un corps (charge utile, données)
Caractéristiques des verbes HTTP :
- Verbes qui ont un corps :
POST
,PUT
,PATCH
- Verbes qui doivent être sûrs (c’est-à-dire qui ne doivent pas modifier les ressources) :
GET
- Verbes qui doivent être idempotents (c’est-à-dire qui ne doivent pas affecter à nouveau les ressources lorsqu’ils sont exécutés plusieurs fois) :
GET
(nullipotent),PUT
,DELETE
body safe idempotent
GET ✗ ✔ ✔
POST ✔ ✗ ✗
PUT ✔ ✗ ✔
DELETE ✗ ✗ ✔
PATCH ✔ ✗ ✗
Par conséquent, les verbes HTTP peuvent être comparés aux fonctions CRUD :
- [Create](https://www.wikiod.com/fr/http/http-pour-les-api#Créer une ressource) : ‘POST’
- READ :
OBTENIR
- [UPDATE](https://www.wikiod.com/fr/http/http-pour-les-api#Modifier une ressource):
PUT
,PATCH
- [DSUPPRIMER](https://www.wikiod.com/fr/http/http-pour-les-api#Supprimer une ressource):
SUPPRIMER
Notez que une requête PUT
demande aux clients d’envoyer la totalité de la ressource avec les valeurs mises à jour. Pour mettre à jour partiellement une ressource, un verbe PATCH
peut être utilisé (voir Comment mettre à jour partiellement une ressource ?).
Statuts de réponse HTTP habituels
Succès
- 201 (CREATED) : la ressource a été créée
- 202 (ACCEPTED) : demande acceptée, mais processus toujours en cours
- 204 (NO CONTENT) : demande satisfaite et aucun contenu supplémentaire
- Sinon : 200 (OK)
Redirection
- 304 (NOT MODIFIED) : le client peut utiliser la version en cache dont il dispose de la ressource demandée
Erreurs client
- 401 (UNAUTHORIZED) : une requête anonyme accède à une API protégée
- 403 (FORBIDDEN) : une requête authentifiée n’a pas assez de droits pour accéder à une API protégée
- 404 (NOT FOUND) : ressource introuvable
- 409 (CONFLIT) : état de la ressource en conflit (par exemple, un utilisateur essayant de créer un compte avec une adresse e-mail déjà enregistrée)
- 410 (GONE) : identique à 404, mais la ressource existait
- 412 (PRECONDITION FAILED) : la requête tente de modifier une ressource qui se trouve dans un état inattendu
- 422 (UNPROCESSABLE ENTITY) : la charge utile de la requête est syntaxiquement valide, mais sémantiquement erronée (par exemple, un champ obligatoire qui n’a pas été valorisé)
- 423 (LOCKED) : la ressource est verrouillée
- 424 (FAILED DEPENDENCY) : l’action demandée dépendait d’une autre action qui a échoué
- 429 (TOO MANY REQUESTS) : l’utilisateur a envoyé trop de requêtes dans un laps de temps donné
- Sinon : 400 (BAD REQUEST)
Erreurs de serveur
- 501 (NOT IMPLEMENTED) : le serveur ne prend pas en charge la fonctionnalité requise pour répondre à la demande
- 503 (SERVICE UNAVAILABLE) : le serveur est actuellement incapable de traiter la demande en raison d’une surcharge temporaire ou d’une maintenance planifiée
- 507 (INSUFFICIENT STORAGE) : le serveur est incapable de stocker la représentation nécessaire pour mener à bien la requête
- Sinon : 500 (ERREUR SERVEUR INTERNE)
Remarques
Rien ne vous empêche d’ajouter un corps aux réponses erronées, pour rendre le rejet plus clair pour les clients. Par exemple, 422 (UNPROCESSABLE ENTITY) est un peu vague : le corps de la réponse doit fournir la raison pour laquelle l’entité n’a pas pu être traitée.
HATEOAS
Chaque ressource doit fournir un hypermédia aux ressources auxquelles elle est liée. Un lien est au moins composé par :
- Un
rel
(pour relation, alias nom) : décrit la relation entre la ressource principale et la ou les ressources liées - Un
href
: l’URL ciblant la ou les ressources liées
Des attributs supplémentaires peuvent également être utilisés pour faciliter la dépréciation, la négociation de contenu, etc.
Cormac Mulhall explique que le client doit décider quel verbe HTTP utiliser en fonction de ce qu’il essaie de faire. En cas de doute, la documentation de l’API devrait de toute façon vous aider à comprendre les interactions disponibles avec tous les hypermédias.
Types de médias
Les types de médias aident à avoir des messages auto-descriptifs. Ils jouent le rôle de contrat entre clients et serveurs, afin qu’ils puissent échanger des ressources et des hypermédias.
Bien que application/json
et application/xml
soient des types de média assez populaires, ils ne contiennent pas beaucoup de sémantique. Ils décrivent simplement la syntaxe globale utilisée dans le document. Des types de médias plus spécialisés qui prennent en charge les exigences HATEOAS doivent être utilisés (ou étendus via vendor media types), tels que :
Un client indique à un serveur quels types de médias il comprend en ajoutant l’en-tête “Accepter” à sa requête, par exemple :
Accept: application/hal+json
Si le serveur n’est pas en mesure de produire la ressource demandée dans une telle représentation, il renvoie un 406 (NOT ACCEPTABLE). Sinon, il ajoute le type de média dans l’en-tête Content-Type
de la réponse contenant la ressource représentée, par exemple :
Content-Type: application/hal+json
Sans état > avec état
Pourquoi?
Un serveur avec état implique que les sessions des clients sont stockées dans un stockage local d’instance de serveur (presque toujours dans des sessions de serveur Web). Cela commence à être un problème lorsque vous essayez de [mettre à l’échelle horizontalement] (http://stackoverflow.com/a/11715598/1225328) : si vous cachez plusieurs instances de serveur derrière un équilibreur de charge, si un client est d’abord envoyé à instance # 1 lors de la connexion, mais ensuite à instance #2 lors de la récupération d’une ressource protégée par exemple, la deuxième instance traitera la demande de manière anonyme, car **la session client a été stockée localement dans *instance #1 ***.
Des solutions ont été trouvées pour résoudre ce problème (par exemple en configurant session replication and/or sticky session), mais l’architecture REST propose une autre approche : il suffit de ne pas rendez votre serveur avec état, * rendez-le sans état *. Selon Fielding:
Chaque requête du client au serveur doit contenir toutes les informations nécessaires à la compréhension de la requête, et ne peut profiter d’aucun contexte stocké sur le serveur. L’état de la session est donc entièrement conservé sur le client.
En d’autres termes, une requête doit être traitée exactement de la même manière, qu’elle soit envoyée à l’instance #1 ou à l’instance #2. C’est pourquoi les applications sans état sont considérées comme * plus faciles à mettre à l’échelle *.
Comment?
Une approche courante est une [authentification basée sur des jetons] (http://stackoverflow.com/a/35316102/1225328), en particulier avec les [jetons Web JSON] à la mode (https://tools.ietf.org/html/rfc7519 ). Notez que JWT a encore quelques problèmes, en particulier concernant l’invalidation et la prolongation automatique de l’expiration (c’est-à-dire la fonction se souvenir de moi).
Notes d’accompagnement
L’utilisation de cookies ou d’en-têtes (ou quoi que ce soit d’autre) n’a rien à voir avec le fait que le serveur soit avec état ou sans état : ce ne sont que des médias qui sont ici utilisés pour transporter des jetons (identifiant de session pour les serveurs avec état, JWT, etc.), rien de plus.
Lorsqu’une API RESTful est uniquement utilisée par les navigateurs, (HttpOnly et [secure](https://en.wikipedia.org/wiki/HTTP_cookie# Les cookies Secure_cookie)) peuvent être très pratiques car les navigateurs les joignent automatiquement aux demandes sortantes. Il convient de mentionner que si vous optez pour les cookies, soyez conscient de CSRF (une bonne façon de l’empêcher est de faire en sorte que les clients générer et envoyer la même valeur secrète unique dans un cookie et un en-tête HTTP personnalisé ).
API pouvant être mise en cache avec [demandes conditionnelles] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests)
Avec l’en-tête Last-Modified
Le serveur peut fournir un en-tête de date “Last-Modified” aux réponses contenant des ressources pouvant être mises en cache. Les clients doivent ensuite stocker cette date avec la ressource.
Désormais, chaque fois que les clients demandent à l’API de lire la ressource, ils peuvent ajouter à leurs requêtes un en-tête “If-Modified-Since” contenant la dernière date de « dernière modification » qu’ils ont reçue et stockée. Le serveur doit alors comparer l’en-tête de la requête et la date réelle de dernière modification de la ressource. S’ils sont égaux, le serveur renvoie un 304 (NOT MODIFIED) avec un corps vide : le client demandeur doit utiliser la ressource actuellement mise en cache. a.
De plus, lorsque les clients demandent à l’API de mettre à jour la ressource (c’est-à-dire avec un verbe non sécurisé), ils peuvent ajouter un [en-tête “If-Unmodified-Since”] (https://tools.ietf.org/html/rfc7232#section- 3.4). Cela aide à gérer les conditions de concurrence : si l’en-tête et la date de dernière modification réelle sont différents, le serveur renvoie un 412 (PRÉCONDITION FAILED). Le client doit alors lire le nouvel état de la ressource avant de réessayer de modifier la ressource.
Avec l’en-tête ETag
Un ETag (balise d’entité) est un identifiant pour un état spécifique d’une ressource. Il peut s’agir d’un hachage MD5 de la ressource pour une validation forte, ou d’un identifiant spécifique au domaine pour un [ validation faible] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests#Weak_validation).
Fondamentalement, le processus est le même qu’avec l’en-tête Last-Modified
: le serveur fournit un en-tête ETag
aux réponses contenant ressources qui peuvent être mises en cache, et les clients doivent alors stocker cet identifiant avec la ressource.
Ensuite, les clients fournissent un If-None-Match
header lorsqu’ils veulent lire la ressource, contenant le dernier ETag qu’ils ont reçu et stocké . Le serveur peut désormais renvoyer un 304 (NOT MODIFIED) si l’en-tête correspond à l’ETag réel de la ressource.
Là encore, les clients peuvent fournir un If-Match
header lorsqu’ils souhaitent modifier la ressource, et le serveur doit renvoyer un 412 (PRÉCONDITION ÉCHEC) si l’ETag fourni ne correspond pas à l’ETag réel.
Notes complémentaires
ETag > date
Si les clients fournissent à la fois la date et l’ETag dans leurs demandes, la date doit être ignorée. De RFC 7232 (ici et ici) :
Un destinataire DOIT ignorer
If-Modified-Since
/If-Unmodified-Since
si la requête contient un champ d’en-têteIf-None-Match
/If-Match
; la condition dansIf-None-Match
/If-Match
est considérée comme un remplacement plus précis de la condition dansIf-Modified-Since
/If-Unmodified-Since
, et les deux ne sont que combinées dans le but d’interopérer avec des intermédiaires plus anciens qui pourraient ne pas implémenterIf-None-Match
/If-Match
.
ETags peu profonds
De plus, bien qu’il soit assez évident que les dates de dernière modification sont conservées avec les ressources côté serveur, plusieurs approches sont disponibles avec ETag.
Une approche habituelle consiste à implémenter des ETags peu profonds : le serveur traite la requête comme si aucun en-tête conditionnel n’avait été donné, mais à la toute fin seulement, il génère l’ETag de la réponse qu’il est sur le point de renvoyer (par exemple en le hachant), et compare avec celui fourni. Ceci est relativement facile à mettre en œuvre car seul un intercepteur HTTP est nécessaire (et de nombreuses implémentations existent déjà en fonction du serveur). Cela étant dit, il convient de mentionner que cette approche économisera de la bande passante mais pas des performances du serveur :
Une implémentation plus approfondie du mécanisme ETag pourrait potentiellement offrir des avantages bien plus importants - comme servir certaines requêtes à partir du cache et ne pas avoir à effectuer le calcul du tout - mais l’implémentation ne serait certainement pas aussi simple, ni aussi enfichable comme l’approche peu profonde décrite ici.
Les pièges courants
Pourquoi ne devrais-je pas mettre de verbes dans une URL ?
HTTP n’est pas RPC : ce qui rend HTTP significativement différent de RPC, c’est que les requêtes sont dirigées vers Ressources. Après tout, URL signifie Uniform Resource Locator, et une URL est un URI : un Uniform Resource Idenfitier. L’URL cible la ressource que vous voulez traiter, la méthode HTTP indique ce que vous voulez en faire. Les méthodes HTTP sont aussi appelées verbes : les verbes dans les URL n’ont alors aucun sens. Notez que les relations HATEOAS ne doivent pas non plus contenir de verbes, car les liens ciblent également des ressources.
Comment mettre à jour partiellement une ressource ?
Comme les requêtes PUT
demandent aux clients d’envoyer la ressource entière avec les valeurs mises à jour, PUT /users/123
ne peut pas être utilisé pour simplement mettre à jour l’email d’un utilisateur par exemple. Comme l’explique William Durand dans S’il vous plaît. Ne patchez pas comme un idiot., plusieurs solutions compatibles REST sont disponibles :
- Exposez les propriétés de la ressource et utilisez la méthode
PUT
pour envoyer une valeur mise à jour, car la spécificationPUT
indique que * des mises à jour partielles du contenu sont possibles en ciblant une ressource identifiée séparément avec un état qui chevauche une partie de la plus grande ressource* :
PUT https://example.com/api/v1.2/users/123/email
body:
[email protected]
- Utilisez une requête
PATCH
contenant un ensemble d’instructions décrivant comment la ressource doit être modifiée (par exemple, en suivant JSON Patch) :
PATCH https://example.com/api/v1.2/users/123
body:
[
{ "op": "replace", "path": "/email", "value": "[email protected]" }
]
- Utiliser une requête
PATCH
contenant une représentation partielle de la ressource, comme proposé dans [Commentaire de Matt Chapman](http://williamdurand.fr/2014/02/14/Please-do-not-patch-like-an- idiot/#commentaire-1495702936):
PATCH https://example.com/api/v1.2/users/123
body:
{
"email": "[email protected]"
}
Qu’en est-il des actions qui ne rentrent pas dans le monde des opérations CRUD ?
Citant Vinay Sahni dans Best Practices for Designing a Pragmatic RESTful API :
C’est là que les choses peuvent devenir floues. Il existe plusieurs approches :
Restructurer l’action pour qu’elle apparaisse comme un champ d’une ressource. Cela fonctionne si l’action ne prend pas de paramètres. Par exemple, une action activate pourrait être mappée à un champ booléen « activé » et mise à jour via un PATCH vers la ressource.
Traitez-la comme une sous-ressource avec les principes RESTful. Par exemple, l’API de GitHub vous permet de star a gist avec
PUT /gists/:id/star
et unstar avecDELETE /gists/:id/star
.Parfois, vous n’avez vraiment aucun moyen de mapper l’action sur une structure RESTful sensible. Par exemple, une recherche multi-ressources n’a pas vraiment de sens pour être appliquée au point de terminaison d’une ressource spécifique. Dans ce cas,
/search
serait le plus logique même s’il ne s’agit pas d’une ressource. C’est OK - faites simplement ce qui est juste du point de vue du consommateur d’API et assurez-vous que c’est clairement documenté pour éviter toute confusion.
Pratiques courantes
-
L’API est documentée. Des outils sont disponibles pour vous aider à construire votre documentation, par ex. Swagger ou Spring REST Docs.
-
L’API est versionnée, soit via les en-têtes, soit via l’URL :
https://example.com/api/v1.2/blogs/123/articles
^^^^
- Les ressources ont [noms au pluriel] (http://stackoverflow.com/a/21809963/1225328) :
https://example.com/api/v1.2/blogs/123/articles
^^^^^ ^^^^^^^^
- Les URL utilisent kebab-case (les mots sont en minuscules et séparés par des tirets) :
https://example.com/api/v1.2/quotation-requests
^^^^^^^^^^^^^^^^^^
- HATEOAS fournit un lien “self” vers les ressources, ciblant elles-mêmes :
{
...,
_links: {
...,
self: { href: "https://example.com/api/v1.2/blogs/123/articles/789" }
^^^^
}
}
- Les relations HATEOAS utilisent lowerCamelCase (les mots sont en minuscules, puis en majuscules sauf le premier, et les espaces sont omis), pour permettre aux clients JavaScript d’utiliser la [notation par points](https://developer.mozilla.org/en-US/docs /Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation) tout en respectant les conventions de nommage JavaScript lors de l’accès aux liens :
{
...,
_links: {
...,
firstPage: { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" }
^^^^^^^^^
}
}
Gestion des blogs via une API HTTP RESTful
Les exemples suivants utilisent HAL pour exprimer HATEOAS et utilisent :
- CURIE (URI compact) : utilisé pour fournir des liens vers la documentation de l’API
- Modèles d’URI : URI qui inclut des paramètres qui doivent être remplacés avant que l’URI ne soit résolu
Obtenir le blog 123
Demande
GET https://example.com/api/v1.2/blogs/123
headers:
Accept: application/hal+json
Réponse
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 123,
"title": "The blog title",
"description": "The blog description",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123" },
"doc:articles": { "href": "https://example.com/api/v1.2/blogs/123/articles{?pageIndex,pageSize}", "templated": true }
}
}
Créer un nouvel article dans le blog 123
Demande
POST https://example.com/api/v1.2/blogs/123/articles
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"title": "The title 2",
"content": "The content 2"
}
Réponse
status: 201 (CREATED)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Obtenir l’article 789 du blog 123
Demande
GET https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
Réponse
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Obtenez la 4ème page des 25 articles du blog 123
Demande
GET https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25
headers:
Accept: application/hal+json
Réponse
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"pageIndex": 4,
"pageSize": 25,
"totalPages": 26,
"totalArticles": 648,
"_link": {
"firstPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" },
"previousPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=3&pageSize=25" },
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25" },
"nextPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=5&pageSize=25" },
"lastPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=26&pageSize=25" }
},
"_embedded": [
{
...
}, {
"id": 456,
"title": "The title 1",
"content": "The content 1",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/456" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/456/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
...
}
]
}
#Mettre à jour l’article 789 du blog 123#
Demande
PUT https://example.com/api/v1.2/blogs/123/articles/789
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated"
}
Réponse
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Remarques
- L’identifiant qui sert à identifier la ressource à mettre à jour est celui de l’URL : celui du corps (le cas échéant) doit être silencieusement ignoré.
- Comme une requête
PUT
met à jour l’ensemble de la ressource, si aucuncontenu
n’aurait été envoyé, il aurait dû être supprimé de la ressource persistante.
Supprimer l’article 789 du blog 123
Demande
DELETE https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
X-Access-Token: XYZ
Réponse
status: 204 (NO CONTENT)
headers:
Content-Type: application/hal+json
body:
{
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" }
}
}
Violation de REST
<stock>
<add>
<item>
<name>Milk</name>
<quantity>2</quantity>
</item>
</add>
</stock>
Mettre ce corps dans une ressource comme /stocks/123
viole l’idée derrière REST.
Bien que ce corps soit “mis” et qu’il contienne toutes les informations nécessaires, il est également accompagné d’un appel de méthode pour “ajouter” quelque part lorsque le corps est traité.
Après REST, on publierait l’élément dans /stocks/123/items/
.