【问题标题】:How should a REST URL schema look like for a tree hierarchy?树层次结构的 REST URL 架构应该如何?
【发布时间】:2011-01-10 03:31:20
【问题描述】:

假设我有商店,商店中有货架,货架上有产品。因此,为了获取商店货架上的产品列表,我将使用以下请求:

GET http://server/stores/123/shelves/456/products

从这里,我将如何获得单个产品?我应该使用:

GET http://server/products/789

或者:

GET http://server/stores/123/shelves/456/products/789

第一种方法更简洁,因为一旦您获得产品列表,如果您只想查看特定产品的详细信息,您并不真正关心它属于哪个商店。但是,第二种方法更合乎逻辑,因为您正在查看特定商店中特定货架的产品。

同样,PUT/DELETE 操作呢?

DELETE http://server/stores/123/shelves/456/products/789

或者:

DELETE http://server/products/789

为这样的树层次结构设计模式的正确方法是什么?

附:如果我对 REST 架构有一些误解,请提供一些示例来说明如何改进。有太多人喜欢说“REST 不是 CRUD”和“REST 不是 RPC”,然后绝对没有提供良好 RESTful 设计的说明或示例。

【问题讨论】:

    标签: url rest schema hierarchy


    【解决方案1】:

    您似乎正在尝试构建许多不同的用例,但一切都被构建到一个超级服务中。最好把它拆开。

    http://server/product_info/123123 or http://server/product_info?product=123123
    http://server/product_inventory?store=123&shelf=345
    

    那么你也可以支持:

    http://server/product_inventory?store=123
    

    然后 PUT 和 DELETE 对于更改库存或添加新产品是有意义的。

    【讨论】:

    • 在 POST 的情况下呢?例如,如果我在货架上添加新产品,我不想做类似POST http://server/product_info/123?shelf=456 这样的事情。
    【解决方案2】:

    创建一个产品应该只是一个 POST 到

    http://server/product
    

    更新产品应该只是一个 PUT 到

    http://server/product/$id
    

    获取产品应该只是获取到

    http://server/product/$id
    

    删除产品应该只是删除

    http://server/product/$id
    

    您应该使用现有的 http 方法从更简单的 uri 结构中获得更多功能。如果创建产品需要通过商店和货架作为要求,那么这些应该在您的 POST 正文中传递(如果您正在更换货架,则应该在 PUT 中传递)。

    当有人对http://server/product/$id 进行 GET 操作时,他们会得到某种 xml/json 响应,对吧?那看起来像什么?创建或更新的传入数据应以相同的方式在请求正文中发布或放置。这就是您在商店和货架中传递的方式,而不是通过 uri。 uri 应该尽可能简单,并且只指向资源(产品),使用 http 动词来区分功能。

    如果您希望能够获取架子 23 的内容,请执行 GET 到

    http://server/shelf/23
    

    当你这样做时,你会得到一个 json / xml / 自定义媒体类型的文档,其中包含货架数据和产品元素的集合,并带有返回其产品 uri 的链接。

    如果您希望能够将产品 23 从一个货架移动到另一个货架,您可以执行 PUT 到

    http://server/product/23 
    

    在 PUT 的正文中,您可以选择代表您选择的产品,但具有更新的货架。

    起初这是一种奇怪的思维方式,因为您不是在处理整个系统的功能,而是专注于资源(产品、货架、商店)并使用 http 动词将它们暴露给宇宙。

    【讨论】:

      【解决方案3】:

      我注意到 RESTful URI 设计的两种方法:分层和过滤

      我觉得层次结构过于冗长,可能存在冗余端点(不是 DRY),并且会伪装成您真正感兴趣的资源状态(毕竟,REST = representational 状态转移)。

      我喜欢简单的 URIs

      简单就是优雅。我会选择一个 URI 结构,例如

      GET http://server/products/789
      

      因为我对产品资源的状态感兴趣。

      如果我想要属于特定商店特定货架的所有产品,那么我会这样做

      GET http://server/products?store=123&shelf=456
      

      如果我想在特定货架上的特定商店创建产品,那么我会发布

      {
          product: {
              store: 123,
              shelf: 456,
              name: "test product"
          }
      }
      

      通过

      POST http://server/products
      

      最终,它是 tomayto,tomahto

      REST 不需要两者相辅相成。但是,根据我自己的经验,使用 RESTful API 将单个实体映射到单个端点(例如:iOS 上的 RestKit 对象映射)而不是根据传递的参数将实体映射到许多不同的端点更有效。

      关于 REST

      就 REST 而言,它不是协议,也没有 RFC。作为实现其 CRUD 操作的一种方式,它与 HTTP/1.1 RFC 紧密相关,但许多软件工程师会认为 REST 不依赖于 HTTP。我不同意并考虑这样的猜想,因为 UCI 的 Roy Fielding (http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm) 的原始论文解释了 REST 和 HTTP/1.1 的根深蒂固的联系。您也可能会喜欢 Roy 对该主题的看法:http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

      REST 定义的原则可以应用于其他协议,但 REST 是为互联网构建的,而 HTTP 是用于万维网的协议。

      REST 与 RPC

      RPC 就是调用远程函数,并且以动词为中心

      REST 就是使用 CRUD 约定根据 CRUD 操作如何应用于给定数据类型来对数据进行操作,并且是以名词为中心的

      您可以使用 REST 或 RPC 完成相同的事情,但 REST 遵循 DRY 原则,因为对于每个 URI,您可以执行 4 个操作,而 RPC 需要每个操作的端点。

      PS

      其中大部分是我的观点,基于我的经验,但我希望它能够帮助您了解如何最有效地设计 RESTful URI 架构。与往常一样,您的具体目标和需求会影响您的选择,但简单性始终是一个很好的目标。

      【讨论】:

        【解决方案4】:

        不要基于 URL 结构设计 REST api。 Here 是我认为您应该如何设计 REST api。

        尝试定义 REST 接口而不讨论哪些链接将包含在哪些资源中就像讨论 RPC 接口并忽略参数和返回值。

        【讨论】:

        • 感谢您的链接。我们只使用网络服务来允许 iPhone 下载和上传数据到服务器(都是内部的),所以看起来我们想要的是 RPC 而不是 REST(可发现性不是问题)。
        • Daniel T:使用 REST 仍有优势。这将使您的客户端对服务器上的更改更加灵活。然后,您的服务器可以随意管理其 URI 空间,而不会破坏客户端。
        • 对于这个应用程序,我们只对在 iPhone 和服务器之间来回发送数据感兴趣,这两者都只在内部使用。构建包含 URL 链接和摘要的对象以及实现在 iPhone 上解析这些数据的方法的成本,比说“这是 API,像这样抓取数据”更昂贵。
        • 只要您接受在以更改其 URI 空间的方式更新服务器时必须更新并重新部署所有客户端,那么 RPC 在这里就可以了。毕竟不需要过度架构东西。但是,请不要错误地将其称为 REST,因为已经有太多人误用了该术语,并且变得相当混乱。
        • 我在一定程度上同意这个答案,但它并没有真正解决问题
        【解决方案5】:

        由于产品可能在多个商店或多个货架(类别?)中,我希望每个产品都有一个唯一编号,无论其在层次结构中的位置如何。然后使用平面产品编号。例如,当某些产品在您的商店中移动时,这会使 API 更加稳定。

        简而言之,不要在您的 API 中添加不必要的冗余。要获得搁置列表,商店 ID 就足够了,对于产品列表,搁置 ID 就足够了......等等。

        【讨论】:

          猜你喜欢
          • 2013-02-21
          • 1970-01-01
          • 2014-10-03
          • 2017-04-18
          • 1970-01-01
          • 2023-03-21
          • 1970-01-01
          • 1970-01-01
          • 2013-02-27
          相关资源
          最近更新 更多