对于树层次结构,REST URL架构应该如何?

时间:2010-01-27 20:54:34

标签: url rest schema hierarchy

我们假设我有商店,商店货架和货架上的产品。因此,为了获得商店货架上的产品清单,我将使用以下请求:

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

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

P.S。如果我误解了有关REST架构的一些内容,请提供有关如何使其更好的示例。有太多人喜欢说“REST不是CRUD”和“REST不是RPC”,那么绝对不提供任何澄清或良好RESTful设计的例子。

5 个答案:

答案 0 :(得分:17)

我注意到了两种RESTful URI设计方法: hierarchy&过滤

我认为层次结构过于冗长,有可能存在冗余端点(而不是DRY),并且伪装成您真正感兴趣的资源状态(毕竟,REST = 具有代表性的状态转移)。 / p>

我赞成简单URI

简单优雅。我会选择像

这样的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对象映射)而不是根据传递的参数将实体映射到许多不同的端点更有效。 / p>

关于REST

就REST而言,它不是协议,也没有RFC。它与HTTP / 1.1 RFC紧密相关,作为实现其CRUD操作的一种方式,但许多软件工程师会认为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架构。与往常一样,您的具体目标和需求将影响您的选择,但简单性始终是目标的良好目标。

答案 1 :(得分:6)

创建产品应该只是一个POST

http://server/product

更新产品应该只是一个PUT

http://server/product/$id

获取产品应该是一个GET

http://server/product/$id

删除产品应该只是一个删除

http://server/product/$id

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

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

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

http://server/shelf/23

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

如果您希望能够将产品23从一个架子移动到另一个架子,那么您需要进行PUT

http://server/product/23 

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

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

答案 2 :(得分:2)

由于产品可能位于多个商店或多个货架(类别?),因此无论其在层次结构中的位置如何,我都会为每个产品提供唯一的编号。然后使用扁平产品编号。这使得API在您的商店中移动时会更加稳定。

简而言之,不要在API中添加不必要的冗余。要获得货架清单,商店ID就足够了,对于产品清单,货架ID就够了......等等。

答案 3 :(得分:2)

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

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

答案 4 :(得分:0)

您似乎正在尝试构建许多不同的用例,但所有内容都将构建到一个超级服务中。打破它会更好。

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对更改库存或添加新产品有意义。