49 votes

REST - applications complexes

J'ai du mal à appliquer Reposant principes d'une nouvelle application web, je travaille sur. En particulier, c'est l'idée que pour être paisible, chaque requête HTTP devraient porter assez d'informations par lui-même pour son destinataire puisse la traiter afin d'être en complète harmonie avec les apatrides de la nature de HTTP.

L'application permet aux utilisateurs de rechercher des médicaments. La recherche accepte les filtres d'entrée, par exemple, le retour abandonnées médicaments, incluent l'accès gratuit à la thérapie, etc..etc. Au total il y a autour de 30 filtres peuvent être appliqués.

En outre, les patients, les détails peuvent être saisis, y compris les patients d'âge, de sexe, de médicaments etc.

Pour être paisible, devraient toutes ces informations seront incluses avec chaque demande? Cela semble placer une surcharge énorme sur le réseau. Aussi, ne pas les restrictions sur la longueur de l'URL, au moins pour OBTENIR, faire ce impossible?

80voto

Will Hartung Points 57465

Le "Filtre Comme Ressource" est un tact parfait pour cela.

Vous pouvez METTRE la définition de filtre pour le filtre de ressources, et peut renvoyer l'ID du filtre.

METTRE est la quantité, de sorte que même si le filtre est déjà là, vous avez juste besoin de détecter que vous avez vu le filtre avant, de sorte que vous pouvez revenir à la bonne ID pour le filtre.

Ensuite, vous pouvez ajouter un paramètre de filtre à vos autres demandes, et qu'ils peuvent saisir le filtre à utiliser pour les requêtes.

GET /médicaments?filtre=1234&page=4&pagesize=20

Je voudrais exécuter le raw filtres à travers une sorte de processus de canonisation, juste pour avoir un normalisée, de sorte que, par exemple, le filtre "firstname=Bob lastname=Eubanks" est identique à "lastname=Eubanks firstname=Bob". C'est juste moi.

Le seul vrai souci, c'est que, comme le temps passe, vous devrez peut-être obsolète de certains filtres. Vous pouvez tout simplement des erreurs de la demande doit-on faire une demande avec un manquants ou obsolètes filtre.

Edit répondre à la question...

Nous allons commencer avec les bases.

Tout simplement, vous souhaitez spécifier un filtre pour une utilisation dans les requêtes, mais ces filtres sont (potentiellement) en cause et compliqué. Si c'était simple /médicaments/1234, ce ne serait pas un problème.

Effectivement, vous avez toujours besoin d'envoyer le filtre de la requête. La question est de savoir comment représenter ce filtre.

Le problème fondamental avec des choses comme des séances en RESTE systèmes est qu'ils sont généralement gérés "hors bande". Lorsque vous, dire, aller et de créer un médicament, vous les METTEZ ou par la POSTE aux médicaments de ressources, et vous obtenez une référence à ce médicament.

Avec une session, vous (généralement) de récupérer un cookie, ou peut-être quelques autres jeton pour représenter cette session. Si votre mise aux médicaments de ressources créé une session aussi, alors, en vérité, votre demande de création de deux ressources: un médicament, et d'une session.

Malheureusement, lorsque vous utilisez quelque chose comme un cookie, et vous avez besoin de ce cookie pour votre demande, le nom de la ressource n'est plus la vraie représentation de la ressource. Maintenant, c'est le nom de la ressource (URL), et le cookie.

Donc, si je fais un GET sur la ressource nommée /médicaments/de recherche, et le cookie représente une session et de la session arrive à avoir un filtre, vous pouvez voir comment, en effet, que le nom de la ressource, /médicaments/de recherche, n'est pas vraiment utile à tous. Je n'ai pas toutes les informations dont j'ai besoin pour faire une utilisation efficace, en raison de l'effet secondaire de cookies et de la session et le filtre qui y sont.

Maintenant, vous pourriez peut-être réécrire le nom: /médicaments/de recherche?session=ABC123, effectivement intégrer le cookie dans le nom de la ressource.

Mais maintenant que vous exécutez dans le typique contrat de sessions, notamment le fait qu'ils sont de courte durée. Ainsi, le nom de la ressource est moins utile, à long terme, et non pas inutile, juste un peu moins utile. Maintenant, cette requête me donne des données intéressantes. Demain? Probablement pas. Je vais prendre une méchante erreur à propos de la session, être allé.

L'autre problème est que les sessions ne sont généralement pas gérée comme une ressource. Par exemple, ils sont généralement un effet secondaire, vs explicitement géré par GET/PUT/DELETE. Des séances sont aussi les "tas d'ordures" de la web app de l'état. Dans ce cas, nous sommes juste en espérant que la session est correctement renseigné avec ce qui est nécessaire pour cette demande. Nous ne savons pas vraiment. Encore une fois, c'est un effet secondaire.

Maintenant, nous allons tourner sur sa tête un peu. Nous allons utiliser /médicaments/de recherche?filtre=ABC123.

Évidemment, mine de rien, cela ressemble à l'identique. Nous avons juste changé le nom de "session" de "filtrer". Mais, comme mentionné, les Filtres, dans ce cas, une "première classe". Ils ont besoin d'être créé, géré, etc. de la même comme un médicament, un JPEG, ou à d'autres ressources dans votre système. C'est la clé de la distinction.

Certes, on pourrait traiter de "sessions" en tant que première classe de ressources, de créer, de mettre des trucs en eux directement, etc. Mais vous pouvez voir comment, au moins à partir d'une clarté point de vue, une "première classe" de la session n'est pas vraiment une bonne abstraction de ce cas. À l'aide d'une session comme aller pour le nettoyage et la remise de la totalité de votre sac à main ou porte-documents. "Oui, le billet est là quelque part, creuser ce que vous voulez, donnez-moi mes vêtements", surtout par rapport à quelque chose d'explicite comme un filtre.

Donc, vous pouvez voir comment, à 30 000 pieds, il n'y a pas beaucoup de différence dans le cas entre un filtre et d'une session. Mais lorsque vous effectuez un zoom avant, ils sont assez différents.

Avec le filtre de ressources, vous pouvez choisir d'en faire une persistance de la chose pour toujours et à jamais. Vous pouvez les supprimer, vous pouvez faire ce que vous voulez. Les séances ont tendance à avoir pré-conçue de la sémantique: court-live, la durée de la connexion, etc. Les filtres peuvent avoir n'importe quelle sémantique que vous voulez. Ils sont totalement distincte de ce qui vient avec une session.

Si je faisais ça, comment pourrais-je travailler avec des filtres?

Je suppose que je n'ai vraiment pas de soins sur le contenu d'un filtre. Plus précisément, je doute que je n'aurais jamais requête pour "tous les filtres de recherche par prénom". À ce stade, il semble inintéressant d'informations, donc je ne le design autour d'elle.

Ensuite, je tiens à normaliser les filtres, comme je l'ai mentionné ci-dessus. Assurez-vous que les filtres équivalents sont vraiment équivalent. Vous pouvez le faire par un tri des expressions, en veillant à fieldnames sont tous en majuscules, ou quoi que ce soit.

Ensuite, je voudrais stocker le filtre que XML ou JSON document, selon ce qui est le plus à l'aise, appropriée pour l'application. Je voudrais donner à chaque filtre d'une clé unique (naturellement), mais je voudrais également stocker une valeur de hachage pour le document lui-même avec le filtre.

Je voudrais faire cela pour être en mesure de trouver rapidement si le filtre est déjà enregistré. Depuis que je suis à les normaliser, je "sais" que le XML (dire) pour logiquement équivalent filtres seraient identiques. Donc, quand quelqu'un va METTRE, ou insérez un nouveau filtre, je voudrais faire un chèque sur la table de hachage pour voir si elle a été stockée à l'avant. Je peut très bien revenir plus d'un (hachages peuvent entrer en collision, bien sûr), donc je vais avoir besoin de vérifier la réelle XML charges pour voir si elles correspondent.

Si les filtres match, je retourne une référence pour le filtre existant. Si non, j'aimerais en créer un nouveau et de retour que.

Je voudrais aussi ne pas permettre une mise à JOUR du filtre/de la POSTE. Depuis que je suis en distribuant des références à ces filtres, je voudrais rendre immuable et les références de validité. Si je voulais un filtre par "rôle", disons, le "get expirent toutes les médicaments filtre", puis je voudrais créer un "filtre" des ressources qui associe un nom à une occurrence de filtre, de sorte que le filtre de données peuvent changer, mais le nom reste le même.

L'esprit, aussi, que lors de la création, vous êtes dans une situation de compétition (deux demandes en essayant de faire le même filtre), de sorte que vous devez tenir compte de cela. Si votre système dispose d'un haut volume de filtration, ce qui pourrait être un goulot d'étranglement potentiel.

Espérons que cela clarifie la question pour vous.

13voto

Rich Apodaca Points 7327

Pour être paisible, devraient toutes ces informations seront incluses avec chaque demande?

Pas de. Si il semble que votre serveur est à envoyer (ou recevoir) des informations trop, les chances sont qu'il y a une ou plusieurs ressources vous n'avez pas encore identifié.

La première et plus importante étape dans la conception d'un système Reposant est d'identifier et de nommer vos ressources. Comment feriez-vous pour que votre système?

À partir de votre description, voici une série de ressources:

  • Utilisateur - utilisateur du système (peut-être un médecin ou patient (?) - Rôle peut-être besoin d'être exposé comme une ressource ici)
  • Médicaments - les trucs dans la bouteille, mais il peut également représenter le genre de bouteille (quantité et le contenu), ou qu'il peut représenter une bouteille particulière - en fonction de si vous êtes une pharmacie ou tout simplement d'un help desk.
  • La maladie - la maladie pour laquelle un Patient voudrez peut-être prendre un Médicament.
  • Patient - une personne qui pourrait prendre un Médicament
  • Recommandation - un Médicament qui pourrait être bénéfique pour un Patient basée sur une Maladie dont ils souffrent.

Alors vous pouvez chercher des relations entre les ressources;

  • L'utilisateur a et appartient à de nombreux Rôles
  • Médicaments a et appartient à de nombreuses Maladies
  • La maladie a beaucoup de Recommandations.
  • Le Patient a et appartient à de nombreux Médicaments et les Maladies (les pauvres chap)
  • Le Patient a beaucoup de Recommandations
  • La recommandation a un Patient et a une Maladie

Les détails sont probablement pas bon pour votre problème particulier, mais l'idée est simple: créer un réseau de relations parmi vos ressources.

À ce stade, il peut être utile de réfléchir à l'URI de la structure, bien garder à l'esprit que les Api REST doit être hypertexte piloté par:

# view all Recommendations for the patient
GET http://server.com/patients/{patient}/recommendations

# view all Recommendations for a Medication
GET http://servier.com/medications/{medication}/recommendations

# add a new Recommendation for a Patient
PUT http://server.com/patients/{patient}/recommendations

Parce que c'est le REPOS, vous passerez la plupart de votre temps de définir les types de supports utilisés pour le transfert des représentations de vos ressources entre le client et le serveur.

En exposant plus de ressources, vous pouvez réduire la quantité de données qui doit être transféré lors de chaque demande. Aussi avis il n'y a pas de paramètres de requête dans l'Uri. Le serveur peut être aussi dynamique qu'il faut pour garder une trace de tout cela, et chaque demande peut être entièrement autonome.

11voto

John Millikin Points 86775

RESTE est pour les Api, pas (typique) des applications. N'essayez pas de coin fondamentalement dynamique de l'interaction dans un apatride modèle juste parce que vous avez lu à ce sujet sur wikipedia.

Pour être paisible, devraient toutes ces informations seront incluses avec chaque demande? Cela semble placer une surcharge énorme sur le réseau. Aussi, ne pas les restrictions sur la longueur de l'URL, au moins pour OBTENIR, faire ce impossible?

La taille de paramètres est généralement négligeable par rapport à la taille de ressources que le serveur envoie. Si vous êtes à l'aide de ces grands paramètres qu'ils sont un réseau de charge, de les placer sur le serveur une fois et ensuite les utiliser comme ressources.

Il n'y a pas d'importantes restrictions à la longueur de l'URL -- si votre serveur dispose d'une telle limite, le mettre à jour. C'est probablement ans et bourré de failles de sécurité, de toute façon.

5voto

Licky Lindsay Points 947

Non, tout cela ne doit pas nécessairement figurer dans chaque demande.

Chaque ressource (médicament, historique du patient, etc.) doit avoir un URI canonique qui l'identifie de manière unique. Dans certaines applications (par exemple, celles basées sur Rails), cela ressemblera à "/ patients / 1234" ou "/ drug / 5678", mais le format de l'URL n'a pas d'importance.

Un client ayant précédemment obtenu l'URI d'une ressource (par exemple, à partir d'une recherche ou d'un lien incorporé dans une autre ressource) peut le récupérer à l'aide de cet URI.

0voto

CoderDennis Points 7170

Travaillez-vous sur une API RESTful que les autres applications utiliser pour rechercher vos données? Ou êtes-vous la construction d'une fin centrées sur les utilisateurs de l'application web, où les utilisateurs pourront se connecter et d'effectuer ces recherches?

Si vos utilisateurs se connectent, alors vous êtes déjà stateful que vous aurez un certain type de cookie de session pour maintenir l'enregistrés dans l'état. Je voudrais aller de l'avant et de créer un objet de session qui contient tous les filtres de recherche. Si un utilisateur n'a pas défini des filtres, puis cet objet sera vide.

Voici un excellent blog sur l'utilisation de GET vs POST. Il mentionne une URL d'une longueur limite fixée par Internet Explorer de 2 048 caractères, de sorte que vous voulez utiliser POST pour les demandes.

http://carsonified.com/blog/dev/the-definitive-guide-to-get-vs-post/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X