良好的RESTful客户端交互 [英] Well-behaving RESTful Client Interactions

查看:82
本文介绍了良好的RESTful客户端交互的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于实现严格遵循REST架构原则的数据访问客户端的一个相当简单的问题。首先,假设我有一个运行良好的REST API,我想使用Django应用程序。我将首先发现有哪些服务可用 (编辑后续)

  GET example.com/services/ HTTP / 1.1 

HTTP / 1.1 200 OK
<?xml version =1.0encoding =UTF-8? >
< services>
< service>
< name> Widgets< / name>
< link> http://example.com/services/widgets/< / link>
< item_link> http://example.com/services/widgets/ {widget_id} /< / item_link>
< / service>
< service>
< name>工厂< / name>
< link> http://example.com/services/factories/< / link>
< item_link> http://example.com/services/factories/ {factory_id} /< / item_link>
< / service>
...
< / services>

现在,由于我正在构建基于消耗此API的Django应用程序,我将如何继续继续探索这些服务吗?要遵守REST原则,我的应用程序必须由接收的超媒体驱动。我想第一步很容易 - 通过给定的名称与服务进行交互。我设置了一个Django视图,如下所示:

  def get_service(request,service_name):
doc = etree.parse (urllib.urlopen('http://example.com/services/'))
uri = doc.xpath(service / name [。='%s'] / following-sibling :: *% service_name)[0] .text
...

从中我将执行另一个请求 (修改后续)

  GET示例。 com / services / widgets / HTTP / 1.1 

HTTP / 1.1 200 OK
<?xml version =1.0encoding =UTF-8?>
< widgets>
< item_link> http://example.com/services/widgets/ {widget_id} /< / item_link>
< widget>
< id> 1< / id>
< name> Whizbang Foobar< / name>
< link> http://example.com/services/widgets/1< / link>
< / widget>
...
< / widgets>

现在,我将在渲染的Django模板中显示一个简单的小部件列表。从这里开始,我如何继续与REST服务进行交互?也许我已经混淆了自己的困惑,但是我可以想出的唯一的事情就是实现大量的应用程序视图或者一个简单的Django数据模型来保持服务URI。



我的主要关注点在于,在严格遵守REST架构指南的情况下,这是微不足道的,但我觉得我完全错过了船所以。我理解设计适当的REST API,客户端不是容易的,但是我似乎迫切需要一个类似的例子来实现实现。





后续行动: strong>



以下是实现这些交互的有效方式(使用URI模板)吗?为了演示目的(代替更抽象的实现),另一个Django视图来检索资源集合项目:

  def get_item请求,service_name,item_id):
doc = etree.parse(urllib.urlopen('http://example.com/services/'))
uri = doc.xpath(service / name [ 。='%s'] / following-sibling :: item_link%service_name)[0] .text
...

然后后续请求:

  GET example.com/services/widgets/1 HTTP / 1.1 

HTTP / 1.1 200 OK
<?xml version =1.0encoding =UTF-8?>
< widget>
< id> 1< / id>
< name> Whizbang Foobar< / name>
< tags> foo bar baz ham eggs< / tags>
< index_link> http://example.com/services/widgets/< / index_link>
< / widget>


解决方案


由于这样做并不是严格遵守REST架构指南,但我觉得我完全错过了这艘船。我理解设计适当的REST API,客户端并不容易,但是我似乎迫切需要一个类似的例子来实现实现。


我能够找到的最好的例子是 Sun云API 。大多数文档描述了系统使用的各种媒体类型,这似乎是拉这种事情的关键。



我发现它有助于在开发您的API的同时编写客户端。这样,您可以发现可能使您的API成为一个痛苦的代码,并解决问题。



这不容易。如果您遵循HATEOAS约束的逻辑结论,您定义的每种媒体类型将由一系列客户端处理。在您可以使所有资源遵循相似的行为模式的情况下,您的客户写作工作将变得更加容易。



例如,您可以定义一个媒体键入索引,只需列出相关资源。索引定义了分页的链接,获取列表中的项目,按名称查找项目等。



然后,您可以定义一个名为Item的基本媒体类型。 Item具有显示其父索引,更新/删除自身等的链接。您的资源Widget可以由两种不同的媒体类型表示 - 一个索引,一个基于Item。



您可以从实现一个处理Index媒体类型的类开始。然后,您可以编写一个处理所有常见项目媒体类型行为的基类。最后,您可以编写一个Widget客户端,处理所有特定于widget的行为,并扩展Item客户端。这些客户端可以以惯用的方式公开他们的功能(更多链接和数据字段的可用性)。



处理您的服务器的响应那么就是将一个mime类型的响应与你所写的客户端进行匹配。



换句话说,即使你的服务的客户端是整个将由许多有限范围的客户组成,它们都将基于常见的行为,因此可以以干式方式实施。


I have what seems to be a fairly simple question about implementing a data access client that strictly adheres to REST architectural principles. To start, let's assume I have a well-behaving REST API that I want to consume using a Django application. I'll start by discovering what services are available (edited for follow-up):

GET example.com/services/ HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<services>
  <service>
    <name>Widgets</name>
    <link>http://example.com/services/widgets/</link>
    <item_link>http://example.com/services/widgets/{widget_id}/</item_link>
  </service>
  <service>
    <name>Factories</name>
    <link>http://example.com/services/factories/</link>
    <item_link>http://example.com/services/factories/{factory_id}/</item_link>
  </service>
  ...
</services>

Now, since I'm building a Django application based around consuming this API, how would I continue to keep exploring these services RESTfully? To adhere to REST principles, my application must be driven by the hypermedia received. I suppose the first step is easy enough -- interacting with a service by the name given. I set up a Django view as follows:

def get_service(request, service_name):
    doc = etree.parse(urllib.urlopen('http://example.com/services/'))
    uri = doc.xpath("service/name[.='%s']/following-sibling::*" % service_name)[0].text
    ...

From which I'll perform another request (edited for follow-up):

GET example.com/services/widgets/ HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<widgets>
  <item_link>http://example.com/services/widgets/{widget_id}/</item_link>
  <widget>
    <id>1</id>
    <name>Whizbang Foobar</name>
    <link>http://example.com/services/widgets/1</link>
  </widget>
  ...
</widgets>

Now I'll display a simple list of widgets in a rendered Django template. From here though, how do I continue to interact with this service RESTfully? Perhaps I've befuddled myself into confusion, but the only reasonable things I can come up with are implementing a numerous amount of application views or a thin Django data model to persist the service URI.

My main concern boils down to that this is trivial to do without strictly adhering to REST architectural guidelines, but I feel like I've missed the boat completely in trying to do so. I understand designing proper REST APIs and clients isn't "easy", but it seems that I'm in dire need of a similar example to work through the actual implementation.

I apologize for the length and verbosity of the question and the inevitable facepalming of wizened readers.

Follow-up:

Is the following a valid way (using URI templates) of implementing these interactions? For demonstration purposes (in lieu of a more abstract implementation), another Django view to retrieve a resource collection item:

def get_item(request, service_name, item_id):
    doc = etree.parse(urllib.urlopen('http://example.com/services/'))
    uri = doc.xpath("service/name[.='%s']/following-sibling::item_link" % service_name)[0].text
    ...

Then the subsequent request:

GET example.com/services/widgets/1 HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <id>1</id>
  <name>Whizbang Foobar</name>
  <tags>foo bar baz ham eggs</tags>
  <index_link>http://example.com/services/widgets/</index_link>
</widget>

解决方案

My main concern boils down to that this is trivial to do without strictly adhering to REST architectural guidelines, but I feel like I've missed the boat completely in trying to do so. I understand designing proper REST APIs and clients isn't "easy", but it seems that I'm in dire need of a similar example to work through the actual implementation.

The best example I've been able to find is the Sun Cloud API. Most of the documentation describes the various media types used by the system, which seems to be the key to pulling this kind of thing off.

I find that it helps to be writing your client at the same time you're developing your API. That way you can spot what's likely to make your API a pain to code for right away and fix the problem.

It isn't easy. If you follow the HATEOAS constraint to its logical conclusion, each media type you define will be handled by one of a family of clients. To the extent that you can make all of your resources follow a similar pattern of behavior, your job of writing clients will become easier.

For example, you could define a media type 'Index' that simply lists related resources. Index defines links for pagination, getting items in the list, finding items by name, etc.

Then, you might define a base media type called 'Item'. Item has a link for displaying its parent Index, updating/deleting itself, etc. Your resource Widget could then be represented by two different media types - one Index and one based on Item.

You could begin by implementing a single class that handles the Index media type. Then you could write a base class that handles all common Item media type behavior. Finally, you could write a Widget client that handles all widget-specific behavior and which extends the Item client. These clients could expose their functionality (availability of more links and data fields) in an idiomatic way for the language they're written in.

Processing a response from your server would then be a matter of matching the mime type of the response to one of the clients you've written.

In other words, even though the client for your service as a whole would be made up of many clients of limited scope, they would each be based on common behaviors and so could be implemented in a DRY way.

这篇关于良好的RESTful客户端交互的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆