Est-ce que quelqu’un connaît un exemple de client RESTful qui suit le principe HATEOAS?

Donc, à présent, je comprends que nous devrions tous mettre en œuvre nos services RESTful en fournissant des représentations qui permettent aux clients de suivre le principe HATEOAS . Et bien que tout cela ait du sens en théorie, j’ai parcouru le Web pour trouver un bon exemple de code client qui suit ssortingctement l’idée.

Plus je lis, plus je commence à avoir l’impression que c’est une discussion académique parce que personne ne le fait réellement! Les gens peuvent se plaindre de toutes les failles de la stack WS- *, mais au moins, il est clair comment écrire des clients: vous pouvez parsingr WSDL et générer du code.

Maintenant, je comprends que cela ne devrait pas être nécessaire avec un bon service RESTful: vous devriez seulement avoir besoin de connaître les relations et les représentations impliquées et vous devriez être capable de réagir dynamicment à celles-ci. Mais même encore, ce principe ne devrait-il pas être distillé et résumé dans certaines bibliothèques courantes? Des informations sur les représentations et les relations que vous pouvez recevoir et un code de niveau supérieur plus utile que vous pouvez utiliser dans votre application?

Ce ne sont là que des idées à moitié réduites, mais je me méfie de savoir que si je plonge et que j’écris une API RESTful correctement, personne ne pourra vraiment l’utiliser! Ou du moins, l’utilisation de ce code sera très pénible à cause des efforts supplémentaires qu’il faudra faire pour écrire le code de la colle afin d’interpréter les relations et les représentations que j’offre.

Est-ce que n’importe qui peut faire la lumière sur ceci du sharepoint vue du client? Est-ce que quelqu’un peut montrer un exemple de code client RESTful correctement dynamic / réactif pour que je puisse avoir une idée du public pour lequel j’écris réellement? (Mieux encore, un exemple d’API client qui fournit des abstractions) Sinon, c’est tout à fait théorique ….

[edit: note, j’ai trouvé une question similaire ici , à laquelle je ne pense pas que la réponse ait été vraiment bonne, l’auteur a été emballé avec un talon Wikipedia!]

Nous avons en quelque sorte fait cela à moitié sur notre projet actuel. Les représentations renvoyées sont générées à partir d’objects de domaine et le client peut les demander soit en XML, JSON ou XHTML. Si c’est un client XHTML comme Firefox, une personne voit un ensemble de liens sortants de la ressource racine bien connue et peut parcourir toutes les autres ressources. Jusqu’à présent, pur HATEOAS, et un excellent outil pour les développeurs.

Mais nous sums préoccupés par les performances lorsque le client est un programme et non un humain utilisant un navigateur. Pour nos représentations XML et JSON, nous avons actuellement supprimé la génération des liens connexes, car ils sortingplent les tailles de représentation et affectent donc considérablement la sérialisation / désérialisation, l’utilisation de la mémoire et la bande passante. Notre autre souci d’efficacité est qu’avec HATEOAS pur, les programmes clients effectuent plusieurs fois le nombre de requêtes HTTP au fur et à mesure qu’ils passent du lien bien connu aux informations dont ils ont besoin. Il semble donc préférable, du sharepoint vue de l’ efficacité , que les clients connaissent les liens qui y sont encodés.

Mais cela signifie que le client doit faire beaucoup de concaténation de chaînes pour former les URI, ce qui est source d’erreurs et rend difficile la réorganisation de l’espace de noms de ressources. Par conséquent, nous utilisons un système de modélisation dans lequel le code client sélectionne un modèle et lui demande de s’étendre à partir d’un object paramètre. C’est un type de remplissage de formulaire.

Je suis vraiment impatient de voir ce que les autres ont vécu à ce sujet. HATEOAS semble être une bonne idée en dehors des aspects de performance.

Edit: Nos templates font partie d’une bibliothèque client Java écrite en haut du framework Restlet . La bibliothèque client gère tous les détails des requêtes / réponses HTTP, des en-têtes HTTP, de la désérialisation / sérialisation, du codage GZIP, etc.

Le blog de Roy Fielding sur HATEOAS a une discussion très pertinente et intéressante qui suit.

Jusqu’à présent, j’ai construit deux clients qui accèdent aux services REST. Les deux utilisent exclusivement HATEOAS. J’ai eu beaucoup de succès à pouvoir mettre à jour les fonctionnalités du serveur sans mettre à jour le client.

J’utilise xml: base pour permettre aux URL relatives de réduire le bruit dans mes documents XML. En dehors du chargement des images et des autres données statiques, je ne fais généralement que suivre des liens sur les requêtes des utilisateurs, de sorte que la surcharge de performances des liens n’est pas significative pour moi.

Sur les clients, la seule fonctionnalité commune que j’ai ressenti le besoin de créer, ce sont les wrappers autour de mes types de média et une classe pour gérer les liens.


Mettre à jour:

Il semble y avoir deux manières distinctes de traiter les interfaces REST du sharepoint vue du client. La première est celle où le client sait quelles informations il souhaite obtenir et connaît les liens qu’il doit parcourir pour accéder à ces informations. La seconde approche est utile lorsqu’un utilisateur humain de l’application client contrôle les liens à suivre et que le client peut ne pas savoir à l’avance quel type de média sera renvoyé par le serveur. Pour la valeur de divertissement, j’appelle ces deux types de client, l’explorateur de données et le répartiteur, respectivement.

Le Data Miner

Par exemple, imaginez un instant que l’API Twitter était en réalité RESTful et que je voulais écrire un client qui récupèrerait le message d’état le plus récent du dernier abonné d’un utilisateur de Twitter donné.

En supposant que j’utilisais l’impressionnante nouvelle bibliothèque Microsoft.Http.HttpClient, et que j’avais écrit quelques méthodes d’extension “ReadAs” pour parsingr le XML provenant de l’API de Twitter, j’imagine que cela pourrait ressembler à ceci:

 var twitterService = HttpClient.Get("http://api.twitter.com").Content.ReadAsTwitterService(); var userLink = twitterService.GetUserLink("DarrelMiller"); var userPage = HttpClient.Get(userLink).Content.ReadAsTwitterUserPage(); var followersLink = userPage.GetFollowersLink(); var followersPage = HttpClient.Get(followersLink).Content.ReadAsFollowersPage(); var followerUserName = followersPage.FirstFollower.UserName; var followerUserLink = twitterService.GetUserLink(followerUserName); var followerUserPage = HttpClient.Get(followerUserLink).Content.ReadAsTwitterUserPage(); var followerStatuses = HttpClient.Get(followerUserPage.GetStatusesLink()).Content.ReadAsTwitterUserPage(); var statusMessage = followerStatuses.LastMessage; 

Le répartiteur

Pour mieux illustrer cet exemple, imaginez que vous implémentiez un client qui rendait des informations de généalogie. Le client doit être capable de montrer l’arborescence, de rechercher des informations sur une personne en particulier et de visualiser des images associées. Considérez l’extrait de code suivant:

  void ProcessResponse(HttpResponseMessage response) { IResponseController controller; switch(response.Content.ContentType) { case "vnd.MyCompany.FamilyTree+xml": controller = new FamilyTreeController(response); controller.Execute(); break; case "vnd.MyCompany.PersonProfile+xml": controller = new PersonProfileController(response); controller.Execute(); break; case "image/jpeg": controller = new ImageController(response); controller.Execute(); break; } } 

L’application client peut utiliser un mécanisme complètement générique pour suivre les liens et transmettre la réponse à cette méthode de répartition. A partir de là, l’instruction switch transmet le contrôle à une classe de contrôleur spécifique qui sait interpréter et restituer les informations en fonction du type de média.

Evidemment, il y a beaucoup plus d’éléments dans l’application cliente, mais ce sont ceux qui correspondent à HATEOAS. N’hésitez pas à me demander de clarifier les points car j’ai parcouru de nombreux détails.

L’ API Places de Nokia est RESTful et utilise l’hypermédia. Il est également clair dans sa documentation de décourager l’utilisation de modèles / codages d’URI:

Utilisation des liens hypermédia

Votre application doit utiliser les liens hypermédias exposés dans les réponses JSON pour les demandes suivantes au sein d’un stream de tâches, au lieu d’essayer de construire un URI pour les étapes suivantes via des modèles d’URI. En utilisant des modèles d’URI, votre demande n’inclut pas les informations critiques requirejses pour créer la réponse à la demande suivante.

Jim, j’étais également un peu frustré par le manque d’exemples avec un client RESTful après HATEOAS, alors j’ai écrit un article de blog montrant un exemple HATEOAS approprié pour créer et passer une commande. Il y a étonnamment peu d’exemples de le faire via une API et je l’ai trouvé un peu déroutant, mais voici le lien: Exemple d’API utilisant Rest . Faites-moi savoir ce que vous pensez et ce que vous pensez que j’ai mal fait.

J’ai écrit deux clients HATEOAS, une fois en Java et une fois en Ruby et je partage votre frustration. Dans les deux cas, il y avait un manque complet de support de l’outillage pour ce que je faisais. Par exemple, l’API REST que j’utilisais me dirait quelle méthode HTTP utiliser pour chaque contrôle hypertexte, mais HttpClient ne vous laisse pas passer la méthode. une tâche Ant personnalisée, d’où le BuildException s):

 private HttpMethod getHypermediaControl(Node href, Node method, NodeList children) { if (href == null) { return null; } HttpMethod control; if (method == null || method.getNodeValue().equals("") || method.getNodeValue().equalsIgnoreCase("GET")) { control = new GetMethod(href.getNodeValue()); } else if (method.getNodeValue().equalsIgnoreCase("POST")) { control = new PostMethod(href.getNodeValue()); } else if (method.getNodeValue().equalsIgnoreCase("PUT")) { control = new PutMethod(href.getNodeValue()); } else if (method.getNodeValue().equalsIgnoreCase("DELETE")) { control = new DeleteMethod(href.getNodeValue()); } else { throw new BuildException("Unknown/Unimplemented method " + method.getNodeValue()); } control.addRequestHeader(accept); return control; } 

Cela a fini par être la base des méthodes utilitaires du client REST que j’utilise.

 private HttpMethod getHypermediaControl(Ssortingng path, Document source) throws TransformerException, IOException { Node node = XPathAPI.selectSingleNode(source, path); return getHypermediaControl(node); } private HttpMethod getHypermediaControl(Node node) { if (node == null) { return null; } NamedNodeMap atsortingbutes = node.getAtsortingbutes(); if (atsortingbutes == null) { return null; } Node href = atsortingbutes.getNamedItem("href"); Node method = atsortingbutes.getNamedItem("method"); HttpMethod control = getHypermediaControl(href, method, node.getChildNodes()); return control; } private Document invokeHypermediaControl(HttpClient client, Document node, final Ssortingng path) throws TransformerException, IOException, HttpException, URIException, SAXException, ParserConfigurationException, FactoryConfigurationError { HttpMethod method = getHypermediaControl(path, node); if (method == null) { throw new BuildException("Unable to find hypermedia controls for " + path); } int status = client.executeMethod(method); if (status != HttpStatus.SC_OK) { log(method.getStatusLine().toSsortingng(), Project.MSG_ERR); log(method.getResponseBodyAsSsortingng(), Project.MSG_ERR); throw new BuildException("Unexpected status code (" + method.getStatusCode() + ") from " + method.getURI()); } Ssortingng strResp = method.getResponseBodyAsSsortingng(); SsortingngReader reader = new SsortingngReader(strResp); Document resp = getBuilder().parse(new InputSource(reader)); Node rval = XPathAPI.selectSingleNode(resp, "/"); if (rval == null) { log(method.getStatusLine().toSsortingng(), Project.MSG_ERR); log(method.getResponseBodyAsSsortingng(), Project.MSG_ERR); throw new BuildException("Could not handle response"); } method.releaseConnection(); return resp; } 

Avec ce petit bout de code, je peux assez facilement écrire des clients qui traverseront les contrôles hypermédia dans les documents renvoyés. Le principal manquant est la prise en charge des parameters de formulaire. Heureusement pour moi, tous les contrôles que j’utilise sont sans paramètre, sauf un (je suis la règle de trois en ce qui concerne le refactoring ). Pour être complet, voici à quoi ressemble l’extrait de code:

  HttpMethod licenseUpdateMethod = getHypermediaControl( "/license/update", licenseNode); if (licenseUpdateMethod == null) { log(getSsortingngFromDoc(licenseNode), Project.MSG_ERR); throw new BuildException( "Unable to find hypermedia controls to get the test suites or install the license"); } else if (license != null) { EntityEnclosingMethod eem = (EntityEnclosingMethod) licenseUpdateMethod; Part[] parts = { new SsortingngPart("license", this.license) }; eem.setRequestEntity(new MultipartRequestEntity(parts, eem .getParams())); int status2 = client.executeMethod(eem); if (status2 != HttpStatus.SC_OK) { log(eem.getStatusLine().toSsortingng(), Project.MSG_ERR); log(eem.getResponseBodyAsSsortingng(), Project.MSG_ERR); throw new BuildException("Unexpected status code (" + eem.getStatusCode() + ") from " + eem.getURI()); } eem.releaseConnection(); } 

Maintenant, ce qu’il faut faire, c’est regarder les enfants de /license/update pour déterminer quels parameters doivent être passés, mais cela devra attendre d’avoir deux formulaires plus paramétrés que je dois suivre .

Après tout l’effort, il a été extrêmement satisfaisant et facile de modifier le serveur sans affecter le client. C’était tellement bon que je suis surpris que ce ne soit pas interdit dans certains États.

Votre navigateur Web de choix est un client “pur HATEOAS” pour l’ensemble du Web.

La question n’a pas vraiment de sens imo.