Pav*_* S. 9 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'
Run Code Online (Sandbox Code Playgroud)
坚持下去,等一下......我写的最后两个标签对产品'123'没有任何说明.是的,评论'abc'属于该产品,但作为一个人,我不需要知道.如果评论ID"abc"在所有评论中都是唯一的,那么计算机也不是.
因此,例如当我们发送更新(PATCH)审核'abc'的请求时,我们不需要知道父对象的整个层次结构直到树根(产品),例如它属于产品'123'在此案件.当然,我们假设每个对象在该实体的所有对象中都有一个唯一的ID - 但这是一种自然行为,例如在RDB中,所以很多人(好吧,他们的API)都处于这种情况.
如果"子实体"的ID在该类型的所有实体中都是唯一的,那么最佳做法是设计这样的API吗?
/reviews/abc ... specific review 'abc'
/reviews/abc/comments ... list comments for review 'abc'
/comments/xyz ... specific comment 'xyz'
Run Code Online (Sandbox Code Playgroud)如果对(1)的回答是肯定的,那么像这样的端点是否也应该有效?为什么?为什么不?
/products/123/reviews/abc/comments/xyz ... specific comment 'xyz'
Run Code Online (Sandbox Code Playgroud)如果允许短URL(甚至是首选),那么这有点不一致吗?
/products/123/reviews ... list reviews for product '123'
/reviews/abc ... specific review 'abc'
/reviews ... what should be here? all reviews?
Run Code Online (Sandbox Code Playgroud)Hon*_*rek 22
/reviews应该是系统中所有评论的列表,但如果这对您的应用程序没有意义,那么/reviews可以产生404,一切都很好.理想情况下,URL的设计应与REST API的其余部分分离.这意味着,就您的网址唯一标识您的资源而言,它们(从纯粹的理论角度来看)是"精心设计的".
但API是一个接口,应该这样对待它.API由机器消耗,但这些机器是由人编写的,因此实际上,设计很重要.这也是为什么在您的博客上设置好网址的原因 - 没有技术原因,但如果用户想要阅读,分享,记住或理解您的网址,则会改善用户的体验(您可能会说Google会搜索关键字)在URL中这是一个技术原因,但不是,它不是 - 谷歌的机器人只是你的用户之一 - 网站消费者 - 机器人的优化就像你的用户的任何其他优化,因此它的界面设计).
如果您的网址设计很重要(出于任何原因),那么在我看来,最好的方法是保持简单.尽可能简单.您的观察是非常正确的 - 您不需要模仿资源的层次结构或数据库中存储数据的方式.最终,它只会妨碍您想要使用API的人.
如果通过ID在集合中唯一标识资源,则只需设计您的URL /collection/{id}.看看Facebook是如何做到的 - 它的大部分API就是这样做的.他们的网址结构非常扁平.
甚至不需要是/collection列出所有现有对象的资源.您可以将它们仅从有意义的/products/123/reviews地方链接,例如,您可以列出指向的链接/reviews/{id}.
将其他ID和层次结构放入URL会使事情变得更加复杂无缘无故.通常,层次结构在API中并不那么简单 - 资源之间的关系通常是非常复杂的图形,而不是简单的树.所以不要把资源之间的链接放到你的URL中 - 有更好的地方(超媒体格式,链接头,或至少通过ID引用链接)在哪里放置有关关系的信息,那些不仅限于一个字符串,如URL,所以他们可以更好地定义关系.
通过在消费者的URL中要求更多信息,您迫使他记住所有这些上下文和所有这些ID或提前知道这些值.您需要更多(不必要的)输入,但实际上,消费者没有理由记住产品的ID只是为了检查其中一个评论.
如果您的网址没有很好地分离,您应该真正考虑如果您的数据结构及时更改会发生什么.使用简单的URL,没有任何实际发生.对于复杂的网址,每次更改API资源的相关方式时,您都需要更改网址,以便他们跟上您的结构.众所周知,改变URL很难 - 无论我们是在谈论网络还是API.超媒体以某种方式解决了这个问题,但即使没有超媒体,你也可以做到至少这么少,以至于你保持你的网址轻松,并且容易变化.
/products/{id} - 特定产品,指向端点及其评论列表的链接/products/{id}/reviews - 列出指向产品评论端点的链接/reviews/{id} - 具体审查,应链接到已审查的产品,它甚至可以链接到上面的列表,如果它似乎对API消费者有用事实上,任何这些资源也可以链接到系统中的任何其他东西,如果它有用或者是否存在逻辑连接.一些链接系统(例如超媒体)使得理解这些链接变得更容易,因为您可以指定一个rel属性,该属性向消费者说明链接指向的位置(self指向自身,next可以指向另一个页面等).
当然,一如既往,这取决于您的具体情况.但一般来说,我建议保持URL分离和简单.此外,我不建议尝试镜像URL中任何复杂的关系或层次结构.