1

为简单起见,假设我有一个资源users。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)中所做的那样引入新资源。

你同意吗?你怎么看?

4

2 回答 2

1

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

为什么不使用带有另一个额外参数的解决方案 1:名称“expect”或“as”。即:users/?fields=name,gender&expect=application/vnd.company.Users+xml users/?fields=name,gender&expect=application/vnd.company.UsersWithFriends+xml

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

于 2011-07-19T11:30:12.567 回答
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(我们:用户,我们:朋友)的文档,描述了资源元素中允许存在哪些数据元素。您可以自由嵌入资源的所有数据,或者更可能只是嵌入数据的子集。如果客户端想要访问嵌入资源的完整表示,那么它可以按照提供的链接。

于 2011-07-19T13:27:36.393 回答