REST中数据的树结构 - URL总是来自root?

时间:2014-03-01 13:30:11

标签: api rest tree restful-url restful-architecture

问题

当数据具有父/子/孙实体的树结构时,我们经常复制URL中的信息,指定父ID,即使这不是必需的。在这种情况下设计RESTful API的最佳方法是什么?可以缩短URL并省略父ID吗?


实施例

树如下:最顶层的实体是产品。每个产品都有0-N评论。每篇评论都附有0-M评论。从理论上讲,这棵树可以有任意深度。

天真的RESTful API看起来像这样(假设只有GET端点):

/products ... list of products
/products/123 ... specific product 123
/products/123/reviews ... list of reviews for product '123'
/products/123/reviews/abc ... specific review 'abc'
/products/123/reviews/abc/comments ... list comments for review 'abc'

坚持下去,等一下......我写的最后两个标签对产品'123'没有任何说明。是的,评论'abc'属于该产品,但作为一个人,我不需要知道。如果审核ID“abc”在所有评论中都是唯一的,那么计算机也不是。

因此,例如,当我们发送更新(PATCH)审核'abc'的请求时,我们不需要知道父对象的整个层次结构直到树根(产品),例如它属于产品'123 ' 在这种情况下。当然,我们假设每个对象在该实体的所有对象中都有一个唯一的ID - 但这是一种自然的行为,例如在RDB中,所以很多人(好吧,他们的API)都处于这种情况。


问题

  1. 如果“子实体”的ID在该类型的所有实体中都是唯一的,那么最佳做法是设计这样的API吗?

    /reviews/abc ... specific review 'abc'
    /reviews/abc/comments ... list comments for review 'abc'
    /comments/xyz ... specific comment 'xyz'
    
  2. 如果对(1)的回答是肯定的,那么此类端点是否也应该有效?为什么?为什么不呢?

    /products/123/reviews/abc/comments/xyz ... specific comment 'xyz'
    
  3. 如果允许使用短网址(甚至是首选网址),那么这有点不一致吗?

    /products/123/reviews ... list reviews for product '123'
    /reviews/abc ... specific review 'abc'
    /reviews ... what should be here? all reviews?
    

2 个答案:

答案 0 :(得分:20)

  1. 取决于 - 我不推荐它,但如果你找到一个用例,为什么不呢?
  2. 我认为没有不一致 - 是的,在这种情况下/reviews应该是系统中所有评论的列表,但如果这对您的应用程序没有意义,那么/reviews可以产生404和一切都很好。

  3. 理想情况下,URL的设计应与REST API的其余部分分离。这意味着,就您的网址唯一标识您的资源而言,它们(从纯粹的理论角度来看)是“精心设计的”。

    但API是一个接口,应该这样对待它。 API由机器消耗,但这些机器是由人编写的,因此实际上,设计很重要。这也是为什么在您的博客上设置好网址的原因 - 没有技术原因,但如果用户想要阅读,分享,记住或理解您的网址,则会改善用户的体验(您可能会说Google会搜索关键字)在URL中这是一个技术原因,但不是,它不是 - 谷歌机器人只是你的用户之一 - 网站消费者 - 机器人的优化就像你的用户的任何其他优化,因此它的界面设计。 / p>


    如果您的网址设计很重要(出于任何原因),那么在我看来,最好的方法是保持简单。尽可能简单。您的观察是非常正确的 - 您不需要模仿资源的层次结构或数据库中存储数据的方式。最终,它只会影响您想要使用API​​的人。

    如果通过ID在集合中唯一标识资源,则只需设计您的网址/collection/{id}。看看Facebook是如何做到的 - 它的大部分API就是这样做的。他们的网址结构非常扁平。

    甚至不需要/collection资源来列出所有现有对象。您可以只在有意义的地方链接它们,例如/products/123/reviews,您可以在其中列出指向/reviews/{id}的链接。

    为什么我认为复杂的网址不好?

    资源之间的关系是图表,您不能将图表放到网址

    将其他ID和层次结构放入URL会使事情变得更加复杂无缘无故。通常,层次结构在API中并不那么简单 - 资源之间的关系通常是非常复杂的图形,而不是简单的树。所以不要把资源之间的链接放到你的URL中 - 有更好的地方(超媒体格式,链接头,或至少linking by ID references)在哪里放置有关关系的信息,那些不仅限于一个字符串,如URL,所以与他们一起,你可以更好地定义关系。

    您通过请求过多参数来折磨您的消费者

    通过在消费者的URL中要求更多信息,您强制他记住所有这些上下文和所有这些ID或提前知道这些值。您需要更多(不必要的)输入,但实际上,消费者没有理由只记得产品的ID以查看其中一条评论。

    进化性

    如果您的网址没有很好地分离,您应该真正考虑如果您的数据结构及时更改会发生什么。使用简单的URL,没有任何实际发生。对于复杂的网址,每次更改API资源的关联方式时,您都需要更改网址,以便他们跟上您的结构。众所周知,改变URL很难 - 无论我们是在谈论网络还是API。超媒体以某种方式解决了这个问题,但即使没有超媒体,你也可以做到至少这么少,以至于你保持你的URL轻松,并且容易变化。

    您的设计可能如下所示

    • /products/{id} - 特定产品,指向端点及其评论列表的链接
    • /products/{id}/reviews - 列出指向产品评论终端的链接
    • /reviews/{id} - 具体审核,应链接到已审核的产品,如果它似乎对API消费者有用,它甚至可以链接到上面的列表

    事实上,任何这些资源也可以链接到系统中的任何其他东西,如果它有用或者是否存在逻辑连接。某些链接系统(例如超媒体)可以更轻松地理解这些链接,因为您可以指定rel属性,该属性向消费者说明链接所指向的位置(self指向自身,{{1} }可以指向另一个页面,等等。)。


    当然,一如既往,这取决于您的具体情况。但一般来说,我建议保持URL分离和简单。另外,我不建议尝试镜像URL中任何复杂的关系或层次结构。

答案 1 :(得分:0)

只要URL可以唯一地标识资源,它就是正确的。

因此,Q-1)和Q-2中的方法都可以使用,并且可以混合使用。这就像为同一资源提供不同的入口点。

问题的答案可以追溯到您的业务用例。如果不需要多个入口点,只需坚持使用一个入口点就可以简化代码。

对于Q-3,'/ reviews'将表示所有评论。如果没有业务用例来获取系统中的所有评论,您也不需要支持。

希望得到这个帮助。