REST - Compromis entre la négociation de contenu via l'en-tête Accept et les extensions

40

Je travaille à la conception d'une API RESTful. Nous savons que nous voulons renvoyer JSON et XML pour une ressource donnée. J'avais pensé que nous ferions quelque chose comme ceci:

GET /api/something?param1=value1
Accept:  application/xml (or application/json)

Cependant, quelqu'un a jeté en utilisant des extensions pour cela, comme ceci:

GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

Quels sont les compromis avec ces approches? Est-il préférable de s'appuyer sur l'en-tête accept lorsqu'une extension n'est pas spécifiée, mais de respecter les extensions lorsqu'elles sont spécifiées? Y a-t-il un inconvénient à cette approche?

Brandon Linton
la source
Quel serveur web utilisez-vous? et comment analyse-t-il les URL?
Dipan Mehta
1
Je n'ai aucune idée du côté technique (serveur) des choses. Cela dit, je préfère votre approche, car elle utilise la norme http, ce qui facilite la compréhension (par exemple, lorsque quelqu'un d'autre est censé effectuer des travaux de maintenance dans quelques années). Vous pouvez vous fier à l'extension lorsque accept n'est pas spécifié ou a une valeur inattendue, mais je choisirais toujours la méthode standard en premier.
Treb
@ Dipan Je corrige cela avec l'API Web MVC4 (toujours en version bêta). Il utilise les abstractions de routage d'ASP.NET, qui sont plutôt sympas.
Brandon Linton
1
@Treb Ouais, je suis bien plus fan de l'utilisation de la valeur d'en-tête accept. Je me demande s'il y a un inconvénient à soutenir les deux.
Brandon Linton

Réponses:

38

Ceci, "Cependant, philosophiquement - la première approche est la seule approche.", Et ceci "La bonne approche officielle REST est d'utiliser Accept: en-tête." sont largement perçus comme étant le cas, mais sont également absolument incorrects .

Voici un bref extrait de Roy Fielding (qui a défini REST) ​​...

"La section 6.2.1 ne dit pas que la négociation de contenu doit être utilisée tout le temps." citer

Cette conversation particulière se situe dans le contexte de l'en-tête "Accept-Language:", mais il en va de même pour l'en-tête "Accepter:", comme cela sera précisé ultérieurement dans sa réponse ...

"Je ne sais pas pourquoi les gens ne peuvent pas voir les deuxième et troisième liens en haut de la page

http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

ce point aux deux éditions PDF. "

Ce qu'il veut dire par là, c'est qu'il n'y a pas de problème à utiliser différents points de terminaison pour différentes représentations des mêmes données source. (Dans ce cas, un point de terminaison .html et deux points de terminaison .pdf différents.)

Toujours dans une discussion similaire, cette fois sur les avantages d'utiliser des paramètres de requête par rapport à l'utilisation d'extensions de fichiers pour différents types de supports ...

"C’est pourquoi je préfère toujours les extensions. Aucun choix n’a rien à voir avec REST." citer

Encore une fois, cela diffère légèrement de l'acceptation par rapport aux extensions de nom de fichier, mais la position de Fielding est toujours claire.

Réponse - peu importe vraiment. Les compromis entre les deux ne sont pas très importants et les deux sont des styles acceptables.

Tom Christie
la source
3
Grande réponse équilibrée. Je pense que j'ajouterais parfois qu'il est "évident" d'après l'URI qu'un certain contenu est destiné. Par exemple, l'extension .html ou .pdf dans l'URI. Et dans ce cas, il n’est vraiment pas nécessaire de prendre en charge la négociation de contenu et le fait d’avoir un contenu implicite dans l’URI facilite le partage de l’URI et son utilisation par les utilisateurs. Dans d'autres cas, par exemple si vous souhaitez éviter les extensions dans vos URI et / ou exposer une API Web prenant en charge plusieurs types de contenu json / XML, un en-tête d'acceptation peut être mieux adapté.
Tim Lovell-Smith
Réponse mise à jour pour contenir de nouveaux liens. Je pense que les groupes yahoo ont changé de structure.
Phil Sturgeon
Je ne suis pas d'accord. Le langage de description de ressource renvoyé par le serveur doit être sans rapport avec la logique applicative exécutée par le noeud final de service. Avoir plusieurs URI pour le même point de terminaison de service, uniquement pour prendre en charge différents langages de description de ressources, semble être une incompréhension de la manière dont les URI REST doivent être construits.
Dejay Clayton
10

L'approche officielle RESTful appropriée consiste à utiliser l'en- Accept:tête.

Cependant, vous devez faire attention à ne pas casser la capacité de mise en cache, qui est l'une des exigences de REST. Vous devez avoir un en- Vary: Accepttête et un cache qui le comprend. Dans un monde idéal, vous l'auriez, mais dans la vie réelle, votre budget peut varier. La deuxième solution n'est donc pas aussi propre, mais elle pourrait être plus pratique.

Notez également que certains très anciens navigateurs ignoraient les en-têtes, s’appuyant plutôt sur l’extension.

vartec
la source
1
Factuellement inexact. Voir la réponse acceptée.
Phil Sturgeon
9

Techniquement, cela n'a pas vraiment d'importance - votre serveur Web sera en mesure de le traiter comme il se doit. (Je suppose cela, mais ne ressemble pas à un obstacle).

Cependant, philosophiquement - la première approche est la seule approche. En mode REST, l’URL pointe en fait uniquement sur un URI - qui n’est qu’une ressource. Pensez un instant à cette ressource comme à un objet en programmation orientée objet. Vous parlez à cette ressource par le biais de seulement 4 méthodes (GET / POST / PUT / DELETE - ou si tout ce que le transport permet), mais cette méthode ne devient pas une description d'objet. De la même manière, la valeur renvoyée par l'aspect n'est pas l'URI. L'objet est toujours quelque chose et non quelque chose.xml ou quelque chose.json

Supposons que si vous ne souhaitez pas utiliser l'en-tête Accept, mais que vous souhaitiez tout de même être véritablement REST philosophiquement, cela ne me dérange pas:

GET /api/something?parm1=value1&return_type=xml

par opposition à

GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

Mais comme je l'ai dit, cette différence n'est que philosophique.

Dipan Mehta
la source
+1 Dipan, vous avez raison, sauf pour une chose: / api / quelque chose? Return_type = xml n'est toujours pas reposant . La raison pour laquelle il n'est pas RESTful est que les URL sont opaques. IOW, du point de vue du protocole, il n'y a pas de différence entre / api / quelque chose / xml et / api / quelque chose? Xml. Voir w3.org/DesignIssues/Axioms.html .
Mark E. Haase
0

@vartec: je pense que tu as tort

Selon le principe officiel RESTful, rien ne doit être caché dans les en-têtes HTTP, car c’est l’URI qui est exposé ou référencé; tout détail de la demande / réponse doit être fourni avec l’URI.

Par conséquent, je recommande fortement d'éviter d'utiliser l'en-tête pour les détails concernant la demande et la réponse, et s'en tenir à

 GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

Je ne parviens pas à trouver rapidement les références, mais je vous répondrai avec elles (vous pouvez vous reporter au livre de publication d'O'reilly "RESTful Web Services" ( http://shop.oreilly.com/product/9780596529260.do ). qui confirme le même

Basav
la source
17
-1 complètement faux. D'une part, l'URL est envoyée dans les en-têtes HTTP. De plus, chaque URL distincte devrait représenter une ressource distincte. Les codages XML et JSON du même contenu ne sont clairement pas 2 ressources différentes; Ce sont 2 représentations différentes de la même ressource.
Mark E. Haase
Les en-têtes HTTP constituent un emplacement légitime et recommandé pour stocker des "métadonnées de messagerie", telles que: informations d'identification de sécurité, identifiant de corrélation, ID de session, contexte transactionnel, formats de données. Ce type d'informations ne doit pas encombrer vos URL ou la charge de vos messages.
Paulo Merson