我一直在尝试构建基于超媒体的API。事情似乎运作良好。当我拿到/books/isbn/12313441213
时,我会得到类似的结果:
<book>
<id>123</id>
<name>Hypermedia APIs</name>
<description>Basic api design techniques</description>
<tags>
<tag>rest</tag>
<tag>api</tag>
<tag>service</tag>
</tags>
<authors>
<link rel="author" uri="/authors/id/22" />
<link rel="author" uri="/authors/id/18" />
</authors>
</book>
现在我可以从这个资源中遍历作者了。当我获取/books/by/author/id/18
时,我会得到类似的内容:
<books>
<book id="123">
<name>Hypermedia APIs</name>
<link rel="self" uri="/books/id/123" />
</book>
<book id="191">
<name>Chef Recipes for Rails Developers</name>
<link rel="self" uri="/books/id/191" />
</book>
<book id="220">
<name>Rails 4 Cookbook</name>
<link rel="self" uri="/books/id/220" />
</book>
<book id="292">
<name>Ruby 102</name>
<link rel="self" uri="/books/id/292" />
</book>
<book id="432">
<name>Semantic Architecture</name>
<link rel="self" uri="/books/id/432" />
</book>
<book id="501">
<name>Service Oriented Design</name>
<link rel="self" uri="/books/id/501" />
</book>
</books>
这对我来说似乎也很好。无论这种uri模板的方式是否良好,我的问题是如何实际遍历这样的链接?
考虑到您需要全面深入的资源(包括作者详细信息),您必须至少对服务器进行3次调用。再次对于集合,您必须对服务器进行大量调用。是的,也许我可以在这里利用资源扩展,但是为什么我会使用超媒体链接,因为我的所有客户都将及时使用扩展资源。
我知道我们通过让客户端遍历链接获得了很多收益(即,如果客户端构建基于关系的资源发现,当我们更改api时,它们将受到最小影响,或者他们被迫从资源中获取最新的模式端点本身等)。然后,这种方法的实用性,或者这种方法的表现会破坏系统。
要么我没有在超媒体api设计中获得某些东西,要么超媒体api听起来不错,但它似乎只是一个理论上的想法,而不是一个实际的想法。
对此有何想法?
答案 0 :(得分:2)
这是一个很好的问题。事实上,另一个重要问题是:谁知道遍历可以达到特定资源R?
例如,要访问“book-detail”资源,客户必须拨打api的条目,例如“/”,然后使用rel“book-categories”获取uri到book-categories然后拨打电话到OPTIONS看看是否可以在该资源上进行GET操作,然后获取图书类别,然后获取rel到“书籍类别”资源......等最终转到“书籍细节”资源。通往资源R的遍历路径应该是客户知识的一部分。但是不要对网址进行硬编码,只需在运行时阅读网址即可。这是考虑机器到人的情况。 效率低下仍然存在。 对于机器到机器的情况,从“/”开始的自动机可以通过您的API并对您的资源进行某些处理。如果自动机必须到达树中的所有资源(或者可能是状态机),那么就没有低效率。但是如果自动机需要在树中调用资源,并且它只知道API的入口点,那么它将运行到几次调用以达到它的问题。
许多人会告诉你使用etags和/或memcached来引入缓存,但缓存是为了增强性能,你不能100%依赖缓存,因为缓存变得陈旧,所以在那些情况下,遍历资源R1到Rn的代码应该在你的客户。
检查我的问题:https://stackoverflow.com/questions/15214526/why-hypermedia-api
但是要回答你关于实用性的问题:如果你有一个业务工作流程,其中客户端需要转到资源R1然后R2然后...... Rn并且你想强制执行该流程,超媒体是实用的。我假设没有直接调用Resource Rx而不通过R1 - &gt; R2 - > ... Rx-1。
答案 1 :(得分:1)
使用参数会更传统:
GET / books?author = 18
我希望回应看起来更像:
超媒体API
您还可以使用参数指示要显示的子资源上的哪些字段。像
这样的东西GET / books / 18?expand = author(姓名,生日)
将返回作者的姓名和生日,作为响应中作者标记的一部分。然后,您可以提供合理的默认值,以确定用户在索要书籍时获得的作者信息量(可能只是作者的自己和姓名),但如果他们想要通过更改参数,他们可以获得更多详细信息。
这些类型的自定义可以帮助减少需要调用的次数。
另一个观察结果是,可以在客户端或中间代理上缓存大量此类数据。关于书籍或作者的可能性不大,因此这些资源可以让客户端长时间缓存它们。然后根本没有往返 - 客户端点击他们自己的本地缓存来获取数据。