【问题标题】:Comparing data with RESTful API使用 RESTful API 比较数据
【发布时间】:2009-11-07 22:33:10
【问题描述】:

对于一个网站,我正在定义一个 RESTful API。我相信我使用正确的资源 URI 和正确使用 GET/POST/UPDATE/DELETE (大部分)正确。

但是有一点我无法完全弄清楚在 REST 中“执行”的正确方法是什么 - 比较列表。

假设我有一家书店,客户可以有一个愿望清单。愿望清单由书籍(它们的完整书籍记录,即名称、概要等)组成,并且该清单的完整副本存在于客户端上。设计 RESTful API 以允许客户端查询其本地愿望清单的正确性(即了解在服务器端的愿望清单上添加/删除了哪些书籍)的好方法是什么?

一种选择是从服务器下载完整的愿望清单并在本地进行比较。然而,这是一个相当大的数据量(由于嵌入的内容),这是一个低带宽连接的移动客户端,所以这会导致很多问题。

另一种选择是不下载整个愿望清单(即不包括图书信息),而只下载图书标识符的列表。这将不会有太多数据(与前一个选项相比),客户端可以在本地比较列表。但是,要获得新添加书籍的完整书籍记录,必须为每一本新书籍进行 REST 调用。同样,由于这是一个网络连接不良的移动客户端,这可能会出现问题。

我最喜欢的第三个选项是客户端将其标识符列表发送到服务器,服务器将其与愿望清单进行比较,并返回删除的书籍和添加的书籍数据。这将意味着一次往返,并且只有必要的数据量。由于愿望清单的大小估计少于 100 个条目,因此仅发送 ID 将是最少量的数据(~0.5kb)。但是我不知道什么样的调用是合适的——它不能是 GET,因为我们正在发送数据(并且把它全部放在 URL 中感觉不对),它不能像我们一样是 POST/UPDATE不改变服务器上的任何东西。显然也不是 DELETE。

您将如何实施这第三个选项?

附带问题:您将如何解决这个问题(即为什么选项 3 愚蠢或有什么更好、更简单的解决方案)?

谢谢。

P.S.:第四个选项是实现一个更复杂的协议,服务器跟踪列表的更改(添加/删除),客户端可以例如根据版本标识符或简单的时间戳查询更改。但是我更喜欢第三种选择,因为它在实现方面更简单,在客户端和服务器上更不容易出错。

【问题讨论】:

  • 除非我弄错了,否则我相信 REST 哲学在其范围内不包括“命令”(因此您的选项 #3 不是 REST-ful)。基于 REST 的接口更类似于“文档管理”接口:创建、删除、更新、检索“部分”等。
  • 只有 Roy Fielding 创建了真正宁静的 API,可惜他从未告诉其他人如何去做。

标签: rest


【解决方案1】:

HTTP 中没有任何内容表明 POST 必须更新服务器。人们似乎忘记了RFC2616 中关于 POST 的一种用法:

  • 提供数据块,例如提交结果 表单,数据处理过程;

将您的客户端愿望清单和发布到唯一目的是返回一组差异的资源没有错。

POST /Bookstore/WishlistComparisonEngine

【讨论】:

    【解决方案2】:

    REST 背后的整个概念是您可以利用底层 HTTP 协议的强大功能。

    在这种情况下,有两个 HTTP 标头可以帮助您确定移动设备上的列表是否过时。另一个好处是您的移动设备上的客户端可能原生支持这些标头,这意味着您无需添加任何客户端代码来实现它们!

    If-Modified-Since: 检查服务器的副本是否在您的客户端第一次检索后更新 Etag:检查客户端本地副本的唯一标识符是否与服务器上的标识符匹配。在服务器上生成 ETag 所需的唯一字符串的一种简单方法是使用 MD5 对服务的文本输出进行哈希处理。

    您可以尝试阅读 Mark Nottingham 的优秀 HTTP caching tutorial,了解这些标头的工作原理。

    如果您使用的是 Rails 2.2 或更高版本,则有 built in support for these headers

    Django 1.1 支持conditional view processing

    this MIX video 展示了如何使用 ASP.Net MVC 实现。

    【讨论】:

    • 好主意!但是,如果它被修改,您仍然需要获取整个列表。或者你能解决这个问题吗?
    • 缓存教程内容丰富。但是我相信最终将是我的代码必须处理所有字段,因此我基本上会实现我在 PS 中概述的第四个选项。
    【解决方案3】:

    我认为这里的关键问题是书籍和愿望清单的定义,以及愿望清单的权威副本保存在哪里。

    我会这样解决问题。首先,您有 Books,它以 ISBN 编号为关键字,并具有描述该书的所有元数据(标题、作者、描述、出版日期、页面等)。然后您有 Wishlists,它们只是 ISBN 编号的列表。您还将拥有客户和其他资源。

    您可以将图书资源命名为:

    /book/{isbn}
    

    和愿望清单资源:

    /customer/{customer}/wishlist
    

    假设您的每位客户都有一份愿望清单。

    权威的愿望清单在服务器上,客户端有一个本地缓存副本。同样,权威书籍在服务器上,客户端有缓存副本。

    Book 表示可以是一个带有元数据的 XML 文档。 Wishlist 表示将是 Book 资源名称的列表(可能还有元数据的 sn-ps)。 Atom 和 RSS 格式似乎很适合愿望清单表示。

    所以你的客户端-服务器同步应该是这样的:

    GET /customer/{customer}/wishlist
    for ( each Book resource name /book/{isbn} in the wishlist )
        GET /book/{isbn}
    

    这完全是 RESTful,让客户端稍后执行 PUT(更新Wishlist)和 DELETE(删除它)。

    这种同步在有线连接上会非常有效,但由于您使用的是移动设备,因此需要更加小心。正如@marshally 指出的,HTTP 1.1 有很多优化特性。请阅读该 HTTP 缓存教程,并确保您的 Web 服务器正确设置 Expires 标头、ETag 等。然后确保客户端具有 HTTP 缓存。如果你的应用是基于浏览器的,你可以利用浏览器缓存。如果您正在开发自己的应用程序,并且找不到要使用的缓存库,您可以编写一个非常基本的 HTTP 1.1 缓存,将返回的表示存储在数据库或文件系统中。缓存条目将按资源名称进行索引,并保存到期日期、实体标签号等。此缓存可能需要几天或一周或两周的时间才能写入,但它是解决同步问题的一般解决方案。

    您还可以考虑对响应使用 GZIP 压缩,因为这可能会将大小减少 60%。所有主要的浏览器和服务器都支持它,如果您的编程语言还没有,您可以使用客户端库(例如,Java 有 GzipInputStream)。

    【讨论】:

      【解决方案4】:

      如果我从您的问题中剔除特定领域的详细信息,我会得到以下信息:

      在您的 RESTful 客户端-服务器应用程序中,客户端存储大型资源的本地副本。客户端需要定期检查服务器以确定其资源副本是否是最新的。

      marshally's suggestion 是使用 HTTP 缓存,IMO 是一种很好的方法,前提是它可以在您的应用程序的约束(例如身份验证系统)内完成。

      缺点是,如果资源以任何方式过时,您将下载整个列表,这在您的情况下听起来不可行。

      相反,首先重新评估是否需要保留愿望清单的本地副本:

      • 您的客户目前如何使用本地愿望清单?
      • 如果必须,您将如何将本地副本替换为从服务器获取的数据?
      • 在构建愿望清单视图和执行业务逻辑时,您采取了哪些措施来最大限度地减少客户的数据需求?

      【讨论】:

      • 好问题,但恐怕已经查过了。客户确实需要完整的愿望清单,并且需要定期更新(这只是一个示例应用程序)。
      【解决方案5】:

      您的第三种选择听起来不错,但我同意它不适合 RESTfull ...

      这是另一个可能有效也可能无效的建议:如果您保留列表的版本历史记录,则可以要求从特定版本开始进行更新。这感觉更像是一个 GET 操作。版本标识符可以是简单的版本号(例如在 svn 中),或者如果您想支持分支或其他非线性历史,它们可以是某种校验和(例如在单调中)。

      免责声明:无论如何,我都不是 REST 哲学或实施方面的专家。

      编辑:在我加载问题后,你有没有为那个 PS 做广告?还是我在写答案之前根本没有完整阅读您的问题?对不起。不过,我仍然认为版本控制可能是个好主意。

      【讨论】:

      • 恐怕我在原文中有 PS,虽然不可否认它不是很突出:)
      猜你喜欢
      • 2013-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 2019-03-08
      相关资源
      最近更新 更多