这是关于服务架构策略的更多问题,我们正在构建基于后端休息服务的大型Web系统。我们目前正在努力建立一些内部标准,以便在开发休息服务时遵循。
有些查询会返回实体列表,例如我们可以考虑让图像库检索服务:/ gell_all_galeries,返回下一个响应:
<galleries>
<gallery>
<id>some_gallery_id</id>
<name>my photos</name>
<photos>
<photo>
<id>123</id>
<name>my photo</name>
<location>http://mysite/photo/show/123</location>
......
<author>
<id>some_id</id>
<name>some name</name>
.......
<author>
</photo>
<photo> ..... </photo>
<photo> ..... </photo>
<photo> ..... </photo>
<photo> ..... </photo>
</photos>
</gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
</galleries>
正如你在这里看到的那样,响应非常庞大而且沉重,而且我们并不总是需要这么深的信息级别。通常的解决方案是为每个图库使用或http://ru.wikipedia.org/wiki/Atom元素而不是完整的图库数据:
<galleries>
<gallery>
<id>some_gallery_id</id>
<link href="http://mysite/gallery/some_gallery_id"/>
</gallery>
<gallery>
<id>second_gallery_id</id>
<link href="http://mysite/gallery/second_gallery_id"/>
</gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
<gallery> .... </gallery>
</galleries>
第一个问题是下一个:也许我们甚至不应该使用和类型,只使用泛型和所有返回列表对象的资源:
<list>
<item><link href="http://mysite/gallery/some_gallery_id"/></item>
<item><link href="http://mysite/gallery/other_gallery_id"/></item>
<item>....</item>
</list>
第二个问题,在用户尝试检索有关某个具体图库的信息之后,他将使用例如http://mysite/gallery/some_gallery_id链接,他应该看到什么结果?
应该是:
<gallery>
<id>some_gallery_id</id>
<name>my photos</name>
<photos>
<photo>
<id>123</id>
<name>my photo</name>
<location>http://mysite/photo/show/123</location>
......
<author>
<id>some_id</id>
<name>some name</name>
.......
<author>
</photo>
<photo> ..... </photo>
<photo> ..... </photo>
<photo> ..... </photo>
<photo> ..... </photo>
</photos>
</gallery>
或:
<gallery>
<id>some_gallery_id</id>
<name>my photos</name>
<photos>
<photo><link href="http://mysite/photo/11111"/></photo>
<photo><link href="http://mysite/photo/22222"/></photo>
<photo><link href="http://mysite/photo/33333"/> </photo>
<photo> ..... </photo>
</photos>
</gallery>
或
<gallery>
<id>some_gallery_id</id>
<name>my photos</name>
<photos>
<photo>
<link href="http://mysite/photo/11111"/>
<author>
<link href="http://mysite/author/11111"/>
</author>
</photo>
<photo>
<link href="http://mysite/photo/22222"/>
<author>
<link href="http://mysite/author/11111"/>
</author>
</photo>
<photo>
<link href="http://mysite/photo/33333"/>
<author>
<link href="http://mysite/author/11111"/>
</author>
</photo>
<photo> ..... </photo>
</photos>
</gallery>
我的意思是如果我们使用链接而不是完整的对象信息,我们应该去那里多深?我应该在照片中显示作者等等。
可能我的问题含糊不清,但我想要做的是在这种情况下制定一般战略,以便所有团队成员在将来都能跟进。
答案 0 :(得分:3)
“我应该如何设计媒体类型”确实没有正确或错误的答案。但是,在选择现有媒体类型和设计新媒体类型时,有一些非常重要的指导原则。
RESTful系统通过谨慎使用缓存来实现可扩展性。设计资源以将内容分解为具有类似数据波动性的块。例如,根据您的方案,您有一个包含照片的图库列表。我的猜测是你不经常添加/删除画廊,但你会定期添加/删除照片。因此,确保您可以获得没有照片信息的画廊列表是有意义的。这样可以轻松缓存该响应。
优化响应的大小对性能很重要,但缓存更为重要。在线上发送0个字节总是更有效。
即使照片列表可能会更频繁地更改,您仍然可以有效地使用缓存。通过使用if-modified-since标头或etags ,您不会保存网络往返,但是您可以通过不传输未更改的表示来节省大量带宽。
设计适合所有情况的资源非常很难因此我建议你不要尝试。设计适合您特定用例的资源。如果出现其他用例,请创建新资源来处理这些用例。
创建没有错:
/gallery/foo/quickview
/gallery/foo/detailedview
/gallery/foo/justlinks
您希望使用一个网页框架,使创建新资源变得非常简单和便宜。资源很少与您的域实体进行一对一映射,因此您可以根据需要随意创建任意数量的资源。
我的最后评论是关于媒体类型的选择。您应该考虑使用像Atom这样的服务。 Atom非常适合管理事物列表,它具有处理照片等媒体元素的所有机制。
大多数人在开始使用REST服务时都会习惯于他们可以直接将application / xml或application / json作为媒体类型提供。在某些特殊情况下,这是完全可行的,但是当您开始实施更多REST约束时,您会发现这些通用媒体类型格式将限制您在许多情况下可以实现的好处。目前,不要太担心它只是意识到选择“真正的”媒体类型如application / xhtml,RDF或Atom总是更安全,如果你选择application / xml你可能会遇到困难以后。
答案 1 :(得分:2)
要考虑的一件好事是您打算如何让客户检索数据。如果您打算让客户端获取有关许多照片的大量信息,那么仅<photo href="..."/>
的列表可能不是最佳的,因为客户端将被迫对每个照片资源执行GET请求他们需要有关的信息。
我可以想到几个有趣的方法来解决这个问题。
您可以允许客户端在查询列表时指定他们要检索的字段作为查询参数,例如:
GET http://www.example.com/photos?_fields=author,fileSize
然后可以返回如下内容:
<photos href="/photos?_fields=author,fileSize">
<photo href="/photos/15">
<author href="/authors/2245"/>
<fileSize>32MB</fileSize>
</photo>
...
</photos>
或者,您可以通过允许客户端指定某种最大“深度”属性来使其更简单;这有点粗糙,但可以有效地使用。例如,如果客户指定深度为2,则会返回<gallery>
下的所有内容,以及每个<photo>
的所有子元素。
GET /galleries?depth=2
可能会返回类似的内容:
<galleries>
<id>22</id>
<name>My Gallery</name>
<!-- full gallery data -->
<photos href="/photos?gallery=/galleries/22">
<photo href="/photos/99">
<id>99</id>
<author href="/authors/4381"/><!-- href instead of including nested author data -->
<fileSize>24MB</fileSize>
<!-- full photo data -->
</photo>
...
</photos>
</galleries>
除此之外,如果您担心客户端一次查询许多记录(例如,如果有数千张照片或图库),您可能需要考虑某种类型的页面分页。这可能涉及为代码中的结果设置最大硬盘,并为客户提供指向下一页/上一页的链接:
GET /photos?gallery=/galleries/59
可能会返回:
<photos href="/photos?gallery=/galleries/59&_max=100&_first=100" next="/photos?gallery=/galleries/59&_max=100&_first=200" prev="/photos?gallery=/galleries/59&_max=100&_first=0" count="100" total="3528">
....
</photos>
客户端可以控制_first
和_max
属性,但在某个配置的阈值上永远不会增加_max
。您将返回标记中页面的“已找到”结果数以及可用结果总数。这可以帮助您减少响应大小,您提到的可能是一个问题。这可以与上面列出的选项并行完成。
最终取决于您希望服务器如何指示客户端检索数据。如果您不希望他们为每张照片执行GET,那么您可能希望为他们提供更方便的方法来获取更深入的数据。但是,如果您认为您的服务器可以处理正常的负载,并且您可以进行服务器端优化(缓存,使用304状态等),那么只返回带有href
s的浅表更简单一点
答案 2 :(得分:1)
这实际上取决于您的情况。您需要知道客户将如何使用它来了解如何设计Resource Proxies。
我建议你不要迷失在“选择十字路口”。根据您对客户端使用情况的假设,选择一个实现。了解整个事物的使用和行为,如果需要,可以随后进行微调。洗净。冲洗。重复。这是永久的Beta方式:)
答案 3 :(得分:0)
您始终可以使用属性。
<gallery id = "1" name = "Gallery 1">
<photos>
<photo id="1" link="http://mysite/photo/11111" />
<photo id="2" link="http://mysite/photo/22222" />
<photo id="3" link="http://mysite/photo/33333" />
</photos>
</gallery>
或者您可以使用JSON我喜欢它,因为它比XML更容易和更轻。
{
"gallery": {
"id": "1",
"name": "Gallery 1",
"photos": [
{
"id": "1",
"link": "http://mysite/photo/11111"
},
{
"photo": "2",
"link": "http://mysite/photo/22222"
},
{
"photo": "3",
"link": "http://mysite/photo/33333"
}
]
}