REST复杂/复合/嵌套资源

我试图围绕解决基于REST的API中的概念的最佳方式。 不包含其他资源的平坦资源不成问题。 我陷入困境的是复杂的资源。

例如,我有一个ComicBook的资源。 ComicBook拥有各种各样的属性,如作者,发行编号,日期等。

一本漫画书也有1..n封面的清单。 这些封面是复杂的对象。 它们包含了很多关于封面,艺术家,日期以及封面的64位编码图像的信息。

对于漫画书上的GET,我只能返回漫画,以及所有封面,包括base64的图片。 这对于获得单个漫画可能不是什么大事。 但是,假设我正在构建一个客户端应用程序,该应用程序想要在表中列出系统中的所有漫画。 该表将包含来自ComicBook资源的一些属性,但我们当然不希望显示表中的所有封面。 返回1000本漫画书,每本书都有多个封面,会导致大量的数据通过网络传播,在这种情况下数据对最终用户来说不是必需的。

我的直觉是让Cover成为资源,ComicBook包含封面。 所以现在Cover是一个URI。 现在在漫画书上工作,而不是大量的Cover资源,我们会为每个封面发送一个URI,客户端可以根据需要检索封面资源。

现在我遇到了创建新漫画的问题。 当我创作漫画时,我打算创作至少一张封面,实际上这可能是一种商业规则。 所以现在我被卡住了,我要么迫使客户强制执行业务规则,首先提交封面,获取封面的URI,然后在列表中发布带有该URI的漫画书,或者我的ComicBook上的POST采用不同的外观资源比它吐出来的要多。 POST和GET的传入资源是深度副本,其中传出GET包含对从属资源的引用。

在任何情况下,封面资源可能都是必要的,因为我确定在某些情况下,我希望作为客户处理封面方向。 因此,不管依赖资源的大小如何,问题都以一般形式存在。 总的来说,您如何处理复杂的资源,而不会强迫客户“知道”这些资源的组成方式?


@ray,优秀的讨论

@jgerman,不要忘记,仅仅因为它是REST,并不意味着资源必须从POST开始设置。

您选择包含在资源的任何给定表示中取决于您。

您分开引用的封面案例仅仅是创建父资源(漫画),其子资源(封面)可能会被交叉引用。 例如,您可能还希望单独提供作者,发布者,角色或类别的参考。 您可能希望单独创建这些资源,或者在将其引用为儿童资源的漫​​画书之前创建这些资源。 或者,您可能希望在创建父资源时创建新的子资源。

你的封面的具体情况稍微复杂一点,因为封面确实需要漫画书,反之亦然。

但是,如果您将电子邮件视为资源,并将发件人地址视为子资源,则显然仍然可以单独引用发件人地址。 例如,获取全部地址。 或者,使用以前的地址创建一条新消息。 如果电子邮件是REST,您可以很容易地看到许多交叉引用的资源可用:/ received-messages,/ draft-messages,/ from-addresses,/ to-addresses,/ addresses,/ subjects,/ attachments / folders ,/ tags,/ categories,/ labels等。

本教程提供了一个交叉引用资源的好例子。 http://www.peej.co.uk/articles/restfully-delicious.html

这是自动生成数据的最常见模式。 例如,您不会发布新资源的URI,ID或创建日期,因为它们是由服务器生成的。 但是,当您获取新资源时,您可以检索URI,ID或创建日期。

以二进制数据为例。 例如,您想要将二进制数据作为子资源进行发布。 获取父资源时,可以将这些子资源表示为相同的二进制数据,或表示二进制数据的URI。

表单和参数已经不同于资源的HTML表示。 发布导致URL的二进制/文件参数不是一个延伸。

当您获取新资源的表单(/ comic-books / new)或获取表单以编辑资源(/ comic-books / 0 / edit)时,您需要获取特定于表单的资源表示形式。 如果使用内容类型“application / x-www-form-urlencoded”或“multipart / form-data”将资源发布到资源集合,则要求服务器保存该类型表示。 服务器可以用保存的HTML表示或其他任何方式进行响应。

出于API或类似目的,您可能还希望允许将HTML,XML或JSON代表发布到资源集合中。

也可以按照您的描述来表示您的资源和工作流程,同时考虑漫画书后张贴的封面,但要求漫画书有封面。 示例如下。

  • 允许延迟创建封面
  • 允许创建具有所需封面的漫画书
  • 允许覆盖被交叉引用
  • 允许多个封面
  • 创建草稿漫画书
  • 创建漫画书封面草稿
  • 发布漫画书草稿
  • GET /漫画书
    => 200好,获取所有漫画书。

    GET /漫画/ 0
    => 200行,带封面的漫画书(id:0)(/封面/ 1,/封面/ 2)。

    GET /漫画/ 0 /封面
    => 200 OK,获取漫画书封面(id:0)。

    GET /覆盖
    => 200好,获取全部封面。

    GET / covers / 1
    => 200行,用漫画(/ comic-books / 0)获取封面(id:1)。

    GET /漫画书/新
    => 200确定,获取表单以创建漫画书(表单:POST /漫画书)。

    POST /漫画书
    名称= foo
    笔者=嘘声
    出版商=咕
    出版= 2011-01-01
    => 302找到,位置:/ draft-comic-books / 3,重定向到带有封面(二进制)的漫画书(id:3)。

    GET / draft-comic-books / 3
    => 200行,获取封面漫画书(id:3)。

    GET /漫画书/ 3 /封面
    => 200 OK,获取草稿漫画书封面(/ draft-comic-book / 3)。

    GET / draft-comic-books / 3 / covers / new
    => 200 OK,获取表格为草稿漫画书(/ draft-comic-book / 3)创建封面(形式:POST /漫画书/ 3 /封面)。

    POST /漫画书/ 3 /封面
    cover_type =前
    cover_data =(二进制)
    => 302发现,地点:/漫画书/ 3 /封面,重定向漫画漫画书的新封面(/ draft-comic-book / 3 / covers / 1)。

    GET / draft-comic-books / 3 /发布
    => 200 OK,获取表格发布漫画书(id:3)(表格:POST /已发布漫画书)。

    POST /已发表漫画书
    名称= foo
    笔者=嘘声
    出版商=咕
    出版= 2011-01-01
    cover_type =前
    cover_data =(二进制)
    => 302找到,位置:/漫画书/ 3,重定向到带封面的漫画书(ID:3)。


    作为资源处理封面绝对是REST的精神,特别是HATEOAS。 所以是的,对http://example.com/comic-books/1GET请求会为您提供book 1的表示,其中包含一组用于封面的URI。 到现在为止还挺好。

    你的问题是如何处理漫画创作。 如果你的商业规则是一本书有0或更多封面,那么你没有问题:

    POST http://example.com/comic-books
    

    使用不露面的漫画书数据将创建一个新的漫画书并返回服务器生成的ID(可以说它回来为8),现在您可以像这样添加封面:

    POST http://example.com/comic-books/8/covers
    

    与在实体的封面。

    现在你有一个很好的问题,如果你的商业规则说总是必须有至少一个封面,那么会发生什么。 以下是一些选择,您在问题中确定的第一个选项:

  • 首先强制创建封面,现在将封面设计为非依赖资源,或者将初始封面放置在创建漫画的POST实体主体中。 这就像你说的那样意味着你创建的表示与你获得的表示不同。

  • 定义主要或初始或首选或其他指定封面的概念。 这可能是一种模型破解,如果你这样做,它就像调整你的对象模型(你的概念或商业模型)以适应技术。 不是一个好主意。

  • 你应该权衡这两种选择,而不是简单地允许不露面的漫画。

    你应该选择哪三种选择? 不知道你的情况太多,但回答一般1..N依赖资源问题,我会说:

  • 如果您可以使用0..N作为您的RESTful服务层,那就太棒了。 如果至少需要一个,那么您的RESTful SOA之间的一层可能会处理进一步的业务约束。 (不知道这是怎么回事,但可能值得探讨......最终用户通常不会看到SOA。)

  • 如果你只是模拟一个1..N的约束条件,那么问自己封面是否只是可共享的资源,换句话说,它们可能存在于漫画除外。 现在他们不是依赖资源,您可以先创建它们,并在您的POST中提供创建漫画书的URI。

  • 如果您需要1..N并且保持依赖,则只需放松自己的本能,以保留POST和GET中的表示,或使它们相同。

  • 最后一项解释如下:

    <comic-book>
      <name>...</name>
      <edition>...</edition>
      <cover-image>...BASE64...</cover-image>
      <cover-image>...BASE64...</cover-image>
      <cover>...URI...</cover>
      <cover>...URI...</cover>
    </comic-book>
    

    当你发布你允许现有的uris时,如果你有它们(从其他书借用),但也可以放入一个或多个初始图像。 如果您正在创建一本书并且您的实体没有初始封面图片,请返回409或类似的回复。 在GET上,您可以返回URI ..

    所以基本上你可以让POST和GET表示“相同”,但你只是选择不在GET上使用封面图像,也不在POST上覆盖。 希望这是有道理的。

    链接地址: http://www.djcxy.com/p/7087.html

    上一篇: REST Complex/Composite/Nested Resources

    下一篇: Which HTTP methods match up to which CRUD methods?