web-dev-qa-db-fra.com

Comment créer REST URL sans verbe?

J'ai du mal à déterminer comment concevoir des URL reposantes. Je suis tout à fait en faveur de l'approche reposante consistant à utiliser des URL avec des noms et les verbes ne comprennent pas comment faire cela.

Nous créons un service pour mettre en place une calculatrice financière. La calculatrice prend un tas de paramètres que nous allons télécharger via un fichier CSV. Les cas d'utilisation impliqueraient:

  1. Télécharger de nouveaux paramètres
  2. Obtenir les derniers paramètres
  3. Obtenir les paramètres pour une date donnée
  4. Rendre un jeu de paramètres actif
  5. Valider un ensemble de paramètres

Je suppose que l'approche reposante consisterait à avoir les URL de type suivantes:

/parameters
/parameters/12-23-2009

Vous pouvez réaliser les trois premiers cas d'utilisation avec:

  1. POST où vous incluez le fichier de paramètres dans la demande de publication
  2. GET de la première URL
  3. GET de la deuxième URL

Mais comment faire les 4ème et 5ème cas d'utilisation sans verbe? N'auriez-vous pas besoin d'URL telles que:

/parameters/ID/activate
/parameters/ID/validate

??

278
Marcus Leon

Peut-être quelque chose comme:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }
71
yfeldblum

Principes généraux pour une bonne conception URI:

  • Ne pas utiliser des paramètres de requête pour modifier l'état
  • Ne pas utiliser des chemins de casse mixtes si vous pouvez l'aider; minuscule est le meilleur
  • N'utilisez pas des extensions spécifiques à votre implémentation dans vos URI (.php, .py, .pl, etc.)
  • Ne pas tomber dans RPC avec vos URI
  • Ne limitez le plus possible votre espace URI
  • Ne Gardez les segments de chemin courts
  • Ne préférez soit /resource ou /resource/; créer 301 redirections à partir de celle que vous n'utilisez pas
  • Faites utiliser des paramètres de requête pour la sous-sélection d'une ressource; c'est-à-dire pagination, requêtes de recherche
  • Faites déplacer des éléments de l'URI qui devraient figurer dans un en-tête HTTP ou un corps

(Remarque: je n'ai pas dit "Conception d'URI RESTful"; les adresses URI sont essentiellement opaques dans REST.)

Principes généraux pour le choix de la méthode HTTP:

  • Ne jamais utiliser GET pour modifier un état; c’est un excellent moyen pour que le Googlebot gâche votre journée
  • Ne pas utiliser PUT sauf si vous mettez à jour une ressource entière
  • Ne pas utiliser PUT sauf si vous pouvez légitimement faire un GET sur le même URI
  • Ne pas utiliser POST pour récupérer des informations qui durent longtemps ou qu'il pourrait être raisonnable de mettre en cache
  • Ne pas effectuer une opération qui n'est pas idempotent avec PUT
  • Ne utilisez GET autant que possible
  • Ne utilisez POST de préférence à PUT en cas de doute
  • Faites utilisez POST chaque fois que vous devez faire quelque chose qui ressemble à RPC
  • Ne utilisez PUT pour les classes de ressources plus grandes ou hiérarchiques
  • Faites utilisez DELETE de préférence à POST pour supprimer des ressources
  • Ne utilisez GET pour des calculs tels que, sauf si votre entrée est grande, auquel cas utilisez POST

Principes généraux de la conception de services Web avec HTTP:

  • Ne pas mettre des métadonnées dans le corps d'une réponse qui devrait figurer dans un en-tête
  • Ne pas ne placez pas les métadonnées dans une ressource distincte, à moins que cela ne crée une surcharge significative
  • Faites utilisez le code d'état approprié
    • 201 Created après la création d'une ressource; la ressource doit exister au moment de l'envoi de la réponse
    • 202 Accepted après une opération réussie ou la création asynchrone d'une ressource
    • 400 Bad Request quand quelqu'un fait une opération sur des données qui sont clairement fausses; pour votre application, cela pourrait être une erreur de validation; réserve généralement 500 pour les exceptions non attrapées
    • 401 Unauthorized lorsque quelqu'un accède à votre API sans fournir d'en-tête Authorization nécessaire ou lorsque les informations d'identification contenues dans Authorization ne sont pas valides; n'utilisez pas ce code de réponse si vous n'attendez pas d'informations d'identification via un en-tête Authorization.
    • 403 Forbidden quand quelqu'un accède à votre API de manière malveillante ou s'il n'est pas autorisé
    • 405 Method Not Allowed quand quelqu'un utilise POST alors qu'il aurait dû utiliser PUT, etc.
    • 413 Request Entity Too Large quand quelqu'un essaie de vous envoyer un fichier trop volumineux
    • 418 I'm a teapotlorsque vous essayez de préparer du café avec une théière
  • Ne utilisez les en-têtes de cache chaque fois que vous le pouvez
    • Les en-têtes ETag sont utiles lorsque vous pouvez facilement réduire une ressource à une valeur de hachage
    • Last-Modified devrait vous indiquer qu'il est judicieux de conserver un horodatage de la mise à jour des ressources.
    • Cache-Control et Expires doivent recevoir des valeurs sensibles
  • Faites tout ce que vous pouvez pour honorer les en-têtes de cache d'une requête (If-None-Modified, If-Modified-Since)
  • Est-ce que utilise les redirections quand elles ont du sens, mais elles devraient être rares pour un service Web

En ce qui concerne votre question spécifique, POST devrait être utilisé pour les points 4 et 5. Ces opérations relèvent de la directive "de type RPC" ci-dessus. Pour le n ° 5, rappelez-vous que POST ne doit pas nécessairement utiliser Content-Type: application/x-www-form-urlencoded. Cela pourrait tout aussi bien être une charge JSON ou CSV.

984
Bob Aman

Lorsque vous avez besoin d'un nouveau verbe, pensez plutôt à le transformer en nom. Par exemple, transformez "activer" en "activation" et "valider" en "validation".

Mais d'après ce que vous avez écrit, votre application pose des problèmes bien plus importants.

Chaque fois qu'une ressource appelée "paramètre" est proposée, elle devrait envoyer des drapeaux rouges dans l'esprit de chaque membre de l'équipe de projet. 'paramètre' peut s'appliquer littéralement à n'importe quelle ressource; ce n'est pas assez précis.

Que représente exactement un "paramètre"? Probablement un certain nombre de choses différentes, dont chacune devrait avoir une ressource distincte dédiée.

Une autre façon d’en arriver à cela: lorsque vous discutez de votre application avec les utilisateurs finaux (ceux qui en savent probablement très peu sur la programmation), quels sont les mots qu’ils utilisent eux-mêmes de manière répétée?

Ce sont les mots avec lesquels vous devriez concevoir votre application.

Si vous n'avez pas encore eu cette conversion avec des utilisateurs potentiels, arrêtez tout maintenant et n'écrivez pas une autre ligne de code avant de le faire! Ce n’est qu’alors que votre équipe aura une idée de ce qui doit être construit.

Je ne connais rien au logiciel financier, mais si je devais deviner, je dirais que certaines des ressources pourraient être nommées, par exemple, "Rapport", "Paiement", "Virement" et "Monnaie".

Il existe un certain nombre de bons livres sur cette partie du processus de conception de logiciels. Deux que je peux recommander sont Conception gérée par le domaine et Modèles d'analyse .

18
Rich Apodaca

La conception de vos URL n'a rien à voir avec le fait que votre application soit RESTful ou non. La phrase "URL RESTful" est donc absurde.

Je pense que vous devriez lire un peu plus sur ce que REST est en réalité. REST traite les URL comme étant opaques et, en tant que telles, ne sait pas ce qu’elles contiennent, s’il existe des verbes, des noms ou autre chose. Vous voudrez peut-être quand même concevoir vos URL, mais il s’agit d’une interface utilisateur, pas de REST.

Cela dit, passons à votre question: les deux derniers cas ne sont pas reposants et ne correspondent à aucun type de régime reposant. Ce sont ce que vous pourriez appeler RPC. Si vous êtes sérieux au sujet de REST, vous devrez repenser le fonctionnement de votre application à partir de la base. Soit ça, soit abandonner REST et créer votre application en tant qu'application RPC.

Hmmmm peut-être pas.

L'idée ici est que vous devez tout traiter comme une ressource. Ainsi, lorsqu'un ensemble de paramètres contient une URL à partir de laquelle vous pouvez vous référer, il vous suffit d'ajouter:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

Mais encore une fois, cette chose active est RPC, pas REST.

11
Breton

Les exigences d'activation et de validation sont des situations dans lesquelles vous essayez de modifier l'état d'une ressource. Il n’est pas différent de faire une commande "terminée" ou une autre demande "soumise". Il existe de nombreuses façons de modéliser ce type de changement d'état, mais l'une des méthodes qui fonctionnent souvent consiste à créer des ressources de collection pour les ressources du même état, puis à déplacer la ressource entre les collections afin d'affecter l'état.

par exemple. Créer des ressources telles que,

/ActiveParameters
/ValidatedParameters

Si vous souhaitez activer un ensemble de paramètres, ajoutez-le à la collection ActiveParameters. Vous pouvez soit passer l'ensemble de paramètres en tant que corps d'entité, soit transmettre une URL en tant que paramètre de requête, comme suit:

POST /ActiveParameters?parameter=/Parameters/{Id}

La même chose peut être faite avec/ValidatedParameters. Si les paramètres ne sont pas valides, le serveur peut renvoyer "Demande incorrecte" à la demande pour ajouter les paramètres à la collection de paramètres validés.

6
Darrel Miller

Je suggérerais les ressources et méthodes Meta suivantes.

Activer les paramètres et/ou les valider:

> PUT /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Connection: close
>
> {'active': true, 'require-valid': true}
>
< HTTP/1.1 200 OK
< Connection: close
<

Vérifiez si les paramètres sont actifs et valides:

> GET /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Connection: close
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Connection: close
<
< {
<     'active': true,
<     'require-valid': true,
<     'valid': {'status': false, 'reason': '...'}
< }
<
1
Andrey Vlasovskikh

Dans un environnement REST, chaque URL est une ressource unique. Quelles sont vos ressources? Une calculatrice financière n'a vraiment pas de ressources évidentes. Vous devez creuser dans ce que vous appelez des paramètres et extraire les ressources. Par exemple, un calendrier d'amortissement pour un prêt peut être une ressource. L'URL du calendrier peut inclure la date de début, la durée (en mois ou en années), la période (lorsque les intérêts sont composés), le taux d'intérêt et le principe initial. Avec toutes ces valeurs, vous avez un calendrier de paiements spécifique:

http://example.com/amort_cal/2009-10-20/30yrsfixed/monthly/5.00/200000

Maintenant, je ne sais pas ce que vous calculez, mais votre concept de liste de paramètres ne sonne pas RESTful. Comme quelqu'un d'autre l'a dit, vos exigences ci-dessus sonnent davantage avec XMLRPC. Si vous essayez de rester, vous avez besoin de noms. Les calculs ne sont pas des noms, ce sont des verbes qui agissent sur les noms. Vous devez le retourner pour extraire les noms de vos calculs.

0
jmucchiello

Edit: En effet, l'URI aurait empêché les requêtes GET de rester idempotentes.


Toutefois, pour la validation, l’utilisation de codes d’état HTTP pour notifier la validité d’une demande (créer un nouveau paramètre ou modifier un paramètre existant) conviendrait au modèle Restful.

Rapportez avec un code de statut 400 Bad Request si les données soumises sont/sont invalides et que la demande doit être modifiée avant d'être soumise à nouveau ( Codes de statut HTTP/1.1 ).

Cela repose toutefois sur la validation au moment de la soumission, plutôt que de la différer comme dans votre cas d'utilisation. Les autres réponses ont des solutions appropriées à ce scénario.

0
Derek Mortimer