【问题标题】:RESTful actions/services that don't correspond to an entity?与实体不对应的 RESTful 操作/服务?
【发布时间】:2011-06-22 00:14:26
【问题描述】:

我喜欢 RESTful,因为它的简单性以及它如何避免像 SOAP 这样的普通“企业”系统的麻烦,或者 DCOM 和 RPC 的二进制硬度。

但是 REST 似乎比更抽象的服务更适合数据库实体。我想知道您是否可以就如何处理这些情况给我建议:

例如,假设我有一个用于普通数据库系统(例如,乳制品购物网站)的 RESTful Web 服务,那么我将拥有 /products/eggs/battery 和 /products/milk/skimmed

执行 INSERT 可以通过向 /products/eggs 发布 POST 来实现。

但是您将如何执行“全部清除”命令? DELETE 动词仅适用于单个实体。 “DELETE /products/milk”意味着删除“牛奶”产品类别本身,而不仅仅是牛奶类别中的所有产品。如果你想同时实现这两个呢?

我的另一个问题与与实体无关的 Web 服务操作有关。例如,如果我正在为密码数据库设计一个 Web 服务,我会执行诸如“GET /passwords/stackoverflow.com”之类的操作,这很好,但我也会有操作来禁用网站以防入侵检测。在“老派”网络服务模型下,我有一个简单命名为“disableWebsite”的方法,但是我无法创建一个名为“DISABLE”的 HTTP 动词和一个名为“/website”的资源(因此请求将是“禁用/网站”)。这里有什么解决办法?

最后,如何协调 HTML 表单和 RESTful? Web 表单只能使用查询字符串或 POST 发出 GET 请求。如果我有一个搜索表单,我希望它请求“/products/search/{query}”,但现在请求看起来像“/products/search?query={query}”。

【问题讨论】:

    标签: rest


    【解决方案1】:

    我认为您应该停止将资源视为数据库实体的同义词。是的,它们通常是相关的,但资源实际上只是您领域中的一个可寻址概念。我认为将资源视为您在使用浏览器时在网络上看到的东西(列表、项目、帖子、cmets、图像等)会更有用。

    但是您将如何执行“全部清除”命令?

    我不确定为什么 DELETE /products/milk 意味着删除牛奶类别本身,但如果您愿意的话:

    DELETE /products?category=milk
    

    DELETE 并不意味着删除单个数据库实体。它意味着删除单个资源。并且“/products?category=milk”(或“/products/milk”,就此而言)标识单个资源。如果你能得到它,你可以删除它。

    如果你想同时实现这两个呢?

    这个怎么样?

    DELETE /product-categories/milk
    

    Ruby on Rails 流行的一个技巧是为任何 PUT/POST/DELETE 操作提供一个表单(使用 GET)。因此,对于这些删除,您可能需要提供这样的表单:

    GET /product-categories/milk/delete
    

    在该表单中(想想 HTML),您可以询问您的用户是否真的可以删除整个类别。(请不要注意 HTML 表单与 RESTful Web 服务并不真正兼容的概念。HTML是一种非常成功的与 web 上的资源交互的格式,一个设计良好的 AJAX 应用程序可能首先作为一个设计良好的 HTML 应用程序工作。有一些细节需要解决以支持浏览器和您的其他客户端,但它们都是合法的 REST 客户端。)

    如何禁用网站?

    有很多方法可以做到这一点。只需对 /sites/stackoverflow.com 使用带有禁用标志的 PUT 即可。

    最后,如何协调 HTML 表单与 RESTful?

    您不能真正从浏览器执行 HTTP PUT 或 DELETE,但您可以在表单中提供一个隐藏字段来伪造它:

    <input type="hidden" name="_method" value="PUT" />
    

    只要您的路由引擎支持它,这是将浏览器帖子路由到适当处理程序的好方法(我还看到人们对非 HTML 客户端使用 X-HTTP-Method-Override 标头而没有完整的支持 HTTP 动词)。

    如果您有兴趣深入研究,我推荐Web Services Cookbook 作为入门。另外,请查看Richardson Maturity Model。请记住,REST 就像 Web 的其他部分一样。如果没有链接,它不会很有用。为您的客户提供一种出行方式。

    <a href="/products/milk/delete" rel="delete" />
    
    <atom:link href="/products/milk/delete" rel="delete" />
    

    【讨论】:

    • 很好的答案!但是使用GET /product-categories/milk/delete 并不是一个真正好的 RESTful 解决方案,因为 GET 是一种保存方法,并且“不应该具有采取除检索之外的操作的意义”参见link。我建议使用POST /product-categories/milk/deletecategory 之类的 POST。这就是 Twitter 使用其 API 处理大量内容的方式。
    • GET 是检索表单,而不是实际执行删除。
    【解决方案2】:

    RESTful 系统与与实体的标准概念无关的“资源”交互。
    “资源”是一个非常模糊的概念,有一些严格的规则。我喜欢将资源视为任何有用的概念,可以帮助客户做他们需要做的事情。 因此,如果您需要删除一堆实体,则创建一个代表该“实体束”的资源,然后对其使用 DELETE 方法。

    设计宁静系统的真正诀窍是停止尝试为特定资源分配重要性,而是为两个资源之间的关系分配重要性。想想 HTML 是如何工作的。您下载一个页面,并且有一个样式表链接。 rel="stylesheet" 定义了您在 href URL 末尾找到的内容的含义。
    如果要禁用网站,请访问网站资源并使用链接中带有 rel="disabler" 的 URL。 RESTful 设计是关于定义通过链接相互关联的资源。一些链接仅用于检索信息,其他链接实际上用于更改资源状态。

    资源必须遵循的严格规则是资源必须具有标识符(例如 URL),并且您只能通过“表示”与该资源进行交互该资源的。这些表示可以采用多种不同的格式。

    对于 HTML 表单,忘记 URI 的样子,使用查询字符串参数就像使用路径参数一样 RESTful。 HTML 表单让您可以进行 GET 和 POST,即安全操作和不安全操作。这对任何人来说都足够了。当然 DELETE 和 PUT 很有用,但实际上这些额外方法给 RESTful 系统带来的好处与超媒体之类的东西相比非常小。

    【讨论】:

      【解决方案3】:

      但是您将如何执行“全部清除”命令? DELETE 动词仅适用于单个实体。

      错误。

      而“DELETE /products/milk”意味着删除“牛奶”产品类别本身,而不仅仅是牛奶类别中的所有产品。

      正确。

      如果你想同时实现这两个呢?

      /cart/milk/ 上的 DELETE 有什么问题?

      在“老派”网络服务模型下,我有一个简单命名为“disableWebsite”的方法,

      什么?

      但是我无法创建一个名为“DISABLE”的 HTTP 动词和一个名为“/website”的资源(因此请求将是“DISABLE /website”)。这里有什么解决办法?

      发布。 POST 到 /passwords/stackoverflow.com/disable/ 实体 (passwords/stackoverflow.com) 在其中包含一个“禁用”和“启用”子实体。您可以发布到任何一个来更改父实体的状态。

      如果我有一个搜索表单,我希望它请求“/products/search/{query}”

      这就是为什么大多数 RESTful Web 服务都是用 Javascript 或 Flex 或类似的东西编写的。

      RESTful Web 服务和“原生”HTML 表单并不真正兼容。他们本不该如此。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多