REST - 允许GET资源/输出不同的版本

时间:2011-07-19 11:10:16

标签: api rest types media representation

为简单起见,我说有一个资源用户。 HTTP调用 GET users / 返回指向具体用户的链接列表:

<users>
    <link rel='user' href='/users/user/1/'/>
    <link rel='user' href='/users/user/2/'/>
    <link rel='user' href='/users/user/3/'/>
    ....
</users>

结果表示以特定媒体类型描述:

application/vnd.company.Users+xml

在我们的前端,我们希望显示一个包含所有用户的表。这意味着我们需要能够获取要显示的用户信息,例如姓名,性别,朋友......我想避免我们需要为每个用户单独请求( GET / users / user / x / )来检索此信息。此外,一些前端只显示名称,而其他前端将显示名称和他/她的朋友。等等。

从本质上讲,我们仍然会返回用户,但是根据前端的需要进行扩展。

您会选择哪个选项?为什么呢?

(1)通过参数自定义 GET用户/ ,以便列出自定义项。根据自定义,可能会返回不同的媒体类型,因为一个版本/组合的语法可能与另一个版本/组合的语法非常不同:

GET users/                            -> application/vnd.company.Users+xml
GET users/?fields=name,gender         -> application/vnd.company.Users+xml
GET users/?fields=name,gender,friends -> application/vnd.company.UsersWithFriends+xml

(2)创建不同的资源以区分不同媒体类型。参数仍用于媒体类型所涵盖的基本自定义。这给出了:

GET users?fields=name                -> application/vnd.company.Users+xml
GET users?fields=name,gender         -> application/vnd.company.Users+xml
GET users_with_friends?fields=gender -> application/vnd.company.UsersWithFriends+xml

(3)与(1)相同,但客户端在Accept标头中设置了所需的媒体类型,而不是参数。媒体类型涵盖的可自定义字段仍然通过参数设置:

GET users/?fields=name        ACCEPT application/vnd.company.Users+xml
GET users/?fields=name,gender ACCEPT application/vnd.company.Users+xml       
GET users/?fields=name,gender ACCEPT application/vnd.company.UsersWithFriends+xml

(4)还有什么?

要回答我自己的问题,我认为:

  • 解决方案(1)非常错误。媒体类型不得依赖于参数。
  • 解决方案(2)和(3)或多或少相等且符合偏好。我更喜欢(3),因为这不会引入大量资源。此外,从本质上讲,我们仍然是返回用户。唯一的区别是返回的不同媒体类型反映的信息量。因此,有人可能会认为没有必要像(2)中那样引入新资源。
你同意吗?你觉得怎么样?

2 个答案:

答案 0 :(得分:1)

(3)使用严格的媒体类型肯定是最好的,但需要特定的HTTP请求客户端,并且无法通过基本的URL打开库或浏览器访问。

为什么不将解决方案1与另一个额外参数一起使用:名称“expect”或“as”。 即: ?用户/字段=姓名,性别和安培;期望值=应用/ vnd.company.Users + xml的 ?用户/字段=姓名,性别和安培;期望值=应用/ vnd.company.UsersWithFriends + xml的

这与ACCEPT解决方案相同,但不需要非常自定义的客户端库来伪造请求。 但是你必须解析参数以提供正确的输出((3)也有解析ACCEPT的要求)

答案 1 :(得分:1)

就个人而言,我不喜欢使用查询字符串参数来允许客户端选择他们希望包含在表示中的数据元素。我发现它很难优化服务器,并且它会污染具有许多重叠变体的缓存。此外,您真的不应该尝试使用conneg在包含不同数据集的表示之间进行选择。 Conneg实际上只是用于选择序列化格式。

使用Hal媒体类型,您可以稍微改变一下这个问题。考虑具有如下所示的根表示的服务:

<resource rel="self" 
          href="http://example.org/userservice"
          xmlns:us="http://example.org/userservice/rels">
   <link rel="us:users" name="users" href="http://example.org/users">
   <link rel="us:userswithfriends" href="http://example.org/userswithfriends">
</resource>

使用hal时,可以使用链接关系,而不是使用媒体类型文档来描述应用程序域。在这种情况下,us:users链接指向包含用户列表的文档。我知道命名空间的东西看起来有点奇怪,但它并没有真正用作XML命名空间,就像制作压缩URI(CURIE)一样。当您创建自己的rel值时,需要以URI的形式指定它们以尝试确保唯一性。

用户列表如下所示:

<resource rel="self" 
          href="http://example.org/users"
          xmlns:us="http://example.org/userservice/rels">

   <resource rel="us:user" name="1" href="/user/1">
      <name>Bob</name>
      <age>45</age>
   <resource>

   <resource rel="us:user" name="2" href="/user/2">
      <name>Fred</name>
      <age>Bill</age>
   <resource>

</resource>

和'us:userswithfriends'指向不同的资源,其中包含每个用户包含朋友列表的用户列表。

<resource rel="self" 
          href="http://example.org/users"
          xmlns:us="http://example.org/userservice/rels">

   <resource rel="us:user" name="1" href="/user/1">
      <name>Bob</name>
      <resource rel="us:friend" name="1" href="/user/10">
        <name>Sheila</name>
      <resource>
      <resource rel="us:friend" name="2" href="/user/74">
        <name>Robert</name>
      <resource>
   <resource>

   <resource rel="user" name="2" href="/user/2">
      <name>Fred</name>
      <resource rel="us:friend" name="1" href="/user/14">
        <name>Bill</name>
      <resource>
      <resource rel="us:friend" name="2" href="/user/33">
        <name>Margaret</name>
      <resource>

   <resource>

</resource>

使用hal,您的rels(us:users,us:friend)的文档描述了资源元素中允许存在哪些数据元素。您可以自由地嵌入资源的所有数据,或者更可能只是数据的一个子集。如果客户端想要访问嵌入资源的完全表示,那么它可以遵循提供的链接。