2010-06-08 75 views
5

这是关于服务架构策略的更多问题,我们正在基于后端的休息服务构建大型Web系统。目前我们正在尝试制定一些内部标准,以开发其他服务。RESTful服务架构问题

某些查询返回的实体的列表,例如让我们考虑我们的图片库中检索服务:/ 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

您可以随时使用属性。

<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" 
      } 
     ] 
    } 
+0

我使用Java和Apache CXF来提供RESTful服务。这具有能够为相同资源提供* XML和JSON两者的优点,这取决于客户说它喜欢什么(即通过内容协商)。 – 2010-06-08 12:46:50

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来返回浅表就更简单了。

+2

我知道让客户选择他们希望接收哪些数据元素的想法是流行的,但是您必须考虑如何严重限制您缓存响应的能力。如果你只有五个属性,那么想象你可能拥有的不同变化的响应数量。你是否缓存了所有这些缓存,并且缓存了它们,缓存了所有这些缓存,并在数据库服务器上增加了额外负载,或者是否缓存在可以从完整缓存副本中提取数据子集的智能中介中? – 2010-06-08 13:00:56

+0

@达雷尔 - 一个好点。这可能取决于服务器是否需要缓存结果。如果不是,那么它是可行的;但如果是这样,我可能会避免它。 – 2010-06-08 13:15:20

+0

@Rob我认为你的想法指定字段名称需要返回是有道理的,因为我记得Linked In Api以这种方式工作。谢谢。 – abovesun 2010-06-08 13:36:06

3

对于“我应该如何设计我的媒体类型”确实没有正确或错误的答案。但是,选择现有和设计新媒体类型时,有几条非常重要的指导原则。

RESTful系统通过谨慎使用缓存来实现可扩展性。设计资源将内容分解成具有类似数据波动性的块。例如,在您的场景中,您有一个包含照片的画廊列表。我的猜测是,你不会经常添加/删除画廊,但你会定期添加/删除照片。因此,确保您可以获得没有照片信息的画廊列表是有意义的。这将使缓存该响应变得容易。

优化响应的大小对于性能可能很重要,但缓存更为重要。通过线路发送0字节总是更高效。

尽管照片列表可能会更经常变化,但您仍然可以有效地使用缓存。通过使用if-modified-since标头或etags,您不会保存网络往返,但可以通过不传输未更改的表示来节省大量带宽。

这是极其难难以设计的资源,非常适合所有情况因此,我建议你不要尝试。适合您的特定用例的设计资源。如果出现其他用例,则创建新资源来处理这些用例。

没有什么错与创建:

/gallery/foo/quickview 
/gallery/foo/detailedview 
/gallery/foo/justlinks 

你想使用Web框架,使得它很容易和便宜,以创建新的资源。资源很少会与您的域实体进行一对一映射,因此请随时创建尽可能多的资源。

我最近的评论是关于媒体类型的选择。你应该真的考虑使用像Atom这样的服务。 Atom非常适合管理事物清单,并且具有处理媒体元素(如照片)的所有机制。

当大多数人开始使用REST服务时,他们习惯于认为他们可以提供直接的application/xml或application/json作为媒体类型。在某些特殊情况下这是完全可行的,但是随着您开始实施更多的REST约束,您会发现这些通用媒体类型格式将限制您在许多情况下可以实现的效益。目前,不要担心太多,只要注意选择application/xhtml,RDF或Atom等“真实”媒体类型总是比较安全的,如果您选择application/xml,则可能遇到困难稍后的。

+0

感谢Darrel,我们从Atom模式取得了链接类型定义,而且我们没有使用Entry或Feed类型。如果你感兴趣,我们正在使用Java Jersey rest实现。 也许我会同意你的陈述,这里没有共同的设计规则,最终的设计决定取决于具体的使用案例。 – abovesun 2010-06-08 13:43:25

1

这真的取决于你的情况。你需要知道客户如何使用这个知道如何设计你的Resource Proxies

我建议你不要迷路在“选择十字路口”。根据您对客户端使用情况的假设进行一次实施。看看整个事情是如何使用和行为的,如果需要的话可以稍后调整。冲洗。重复。做它永久的Beta方式:)