RESTful API URI 设计
Posted
技术标签:
【中文标题】RESTful API URI 设计【英文标题】:RESTful API URI Design 【发布时间】:2012-10-23 20:45:03 【问题描述】:我正在寻找有关 RESTful API 的 URI 设计的方向。我将有几个嵌套的链接资源,目前我设计的 URI 类似于这篇文章:Hierarchical RESTful URL design
以下示例不是我正在构建的示例,但我认为很好地说明了我的情况。 (假设一个节目只能属于一个网络)。
/networks [GET,POST]
/networks/network_id [GET,PUT]
/networks/network_id/shows [GET,POST]
/networks/network_id/shows/show_id [GET,PUT]
/networks/network_id/shows/show_id/episodes [GET,POST]
/networks/network_id/shows/show_id/episodes/episode_id [GET,PUT]
我的情况将通过关联进一步发展两个层次,但所有关联都是一对多的。我正在考虑将其切换为类似于以下内容:
/networks [GET,POST]
/networks/network_id [GET,PUT]
/networks/network_id/shows [GET,POST]
/shows [GET]
/shows/id [GET,PUT]
/shows/id/episodes [GET,POST]
/episodes [GET]
/episodes/id [GET,PUT]
我的问题是:
-
第二个示例是有效的 REST 设计吗?
我应该考虑同时实现这两条路径吗?
【问题讨论】:
请记住,您最终决定了 RESTful API 的结构。将使用它的是您的客户。我认为两者都很好,尽管显然第一个更擅长说明网络、节目和剧集之间的层次结构。但是,如果 URI 变得异常长,那么将这些实体分离到 / 下也不是很疯狂。我会问自己,实际上哪些资源会被使用得最多。如果是剧集和节目,那么将它们放在基础之下很有意义。 【参考方案1】:第二个例子对我来说很好。 URL 描述了资源,并且使用了正确的 HTTP 动词。
如果有意义的话,让多个 URL 指向同一个资源是完全可以的。但更重要的是,确保资源包含 <link />
元素,这些元素将节目与网络、剧集与节目等联系起来。
【讨论】:
+1:我自己更喜欢xlink:href
属性,但<link>
元素也不错。
属性在 XML/Xhtml 中运行良好,但像 JSON 这样的一些表示不支持它们。无论如何,重要的是利用超媒体让服务真正实现 RESTful。【参考方案2】:
真正的问题是:您的第二个示例是否满足 URI 标准? URI 标准规定,路径包含分层部分,查询包含非分层部分,但是 afaik。它没有说明如何在您的情况下设计 URI 结构。 REST 统一接口约束有一个 HATEOAS 部分,这意味着您应该在您的情况下发回指向上层和下层资源的链接。您应该使用元数据注释这些链接,这些元数据可以由客户端处理,因此它会知道链接是关于什么的。所以在实践中,URI 结构并不重要......
GET /shows/123
"label": "The actual show",
"_embedded":
"episodes": [
"label": "The first episode of the actual show",
"_embedded":
"associations": [
//...
]
,
"_links":
"self":
"label": "Link to the first episode of the actual show",
"href": "/episodes/12345"
,
"first":
"href": "/episodes/12345"
,
"duplicate":
"href": "/networks/3/shows/123/episodes/12345"
,
"up":
"label": "Link to the actual show",
"href": "/shows/123"
,
"next":
"label": "Link to the next episode of the actual show"
"href": "/episodes/12346"
,
"previous": null,
"last":
"href": "/episodes/12350"
//,
//...
]
,
"_links":
"self":
"label": "Link to the actual show",
"href": "/shows/123"
,
"duplicate":
"href": "/networks/3/shows/123"
,
"up":
"label": "Link to the actual network",
"href": "/networks/3"
,
"collection":
"label": "Link to the network tree",
"href": "/networks"
,
"next":
"label": "Link to the next show in the actual network",
"href": "/shows/124"
,
"previous":
"label": "Link to the previous show in the actual network",
"href": "/shows/122"
现在这只是 HAL+JSON 中带有 IANA 链接关系的测试版,但您也可以将 JSON-LD 与 RDF 词汇表(例如 schema.org+hydra)一起使用。这个例子只是关于层次结构(上,第一个,下一个,上一个,最后一个,集合,项目等......),但您应该添加更多元数据,例如哪个链接指向一个网络,哪个指向一个节目,哪个指向一集,等等……所以您的客户将从元数据中知道内容是关于什么的,例如,他们可以使用这些链接自动导航。这就是 REST 的工作方式。所以 URI 结构对客户端来说并不重要。 (如果您想让响应更紧凑,也可以使用紧凑 URI 和 URI 模板。)
【讨论】:
【参考方案3】:URI 是“任何可以命名的信息”
您的问题是与域相关的问题,只有知道您使用 URI 命名的资源的人才能真正回答。
在尝试猜测您的域时想到的问题是,“节目”真的依赖于“网络”吗?
您的域中的网络是什么?节目和网络是什么关系?只是单纯的播过节目的人吗?还是更多地与生产信息有关?
我相信您的示例 2 更合适。
【讨论】:
【参考方案4】:考虑到您在以下层次结构中有一对多关系:
network --> shows --> episodes
我认为第二种设计没有向服务器端提供足够的信息来处理您的请求。例如,如果您有以下数据:
Network id show_id episode_id
1 1 1
1 2 1
1 1 2
第一个详细的设计将在 HTTP 请求中提供足够的信息来获取数据:/networks/1/shows/1/episodes/1
相反的第二种设计将有:
/episodes/1
在第二种设计中,服务器端无法知道您是指数据中的第 1 行还是第 2 行
回答你的问题:
恕我直言,第二个设计对于您的示例可能不是有效的 REST 设计。一种 解决方法可能是传递查询参数
我认为设计 1 是自给自足的
更新:请忽略我上面的回答
-
第二个设计是您的示例的有效 REST 设计
只有设计 2 就足够了
另外:
/networks
/networks/id
/shows
/shows/id
/episodes
/episodes/id
应该有足够数量的 REST URL
或者换句话说,以下 URL 将是多余的:
/networks/network_id [GET,PUT]
/networks/network_id/shows [GET,POST]
/shows/id/episodes [GET,POST]
【讨论】:
亲爱的 Vikram,如果我误解了,请纠正我,您是否建议剧集正确设计需要 3 列复合主键? @AlessandroOliveira 感谢您的评论。你的评论帮助我理解了问题中的第二个设计也是一个有效的设计!!回答您的问题:3 列复合主键只是理解这 3 个分层实体之间关系的一种表示。我不是要推荐它... 我非常关心的另一件事是将主键暴露为对象 ID,我认为即使系统具有身份验证和授权措施,这些实施决策也不应该暴露在任何大大地。但由于我是 UUID 的拥护者,我的立场也算是有点偏颇了。 @AlessandroOliveira 我同意你的看法【参考方案5】:我认为我们应该使 REST API URL 尽可能简单。
例如https://www.yoursite.com/api/xml/1.0/
这里我以 1.0 版的 XML API 为例。请记住使用 API 版本以供将来更新。
您可以查看客户端请求的方法。
e.g. tag
<method>getEpisodes</method>
【讨论】:
这看起来不是特别 RESTful,而是非常 SOAPy(如果您正在这样做,这没关系,但是 SOAP 和 REST 是构建应用程序的非常不同的方法......) 我主要关心的是 API 的版本。例如我的稳定 API 版本是 1.2,我的客户在他们的应用程序中使用相同的版本。现在我们增强了我们的 API(1.4 版)并弃用了 1.2 版支持的 API 的一些功能。我使用 1.2 版的客户将收到有关已弃用功能的错误。请告诉我你的想法。【参考方案6】:我认为第二个选项还可以,但如果您想验证关系,我会考虑第一个选项。例如,当您使用不同的网络获得一集时,这可能意味着该集在您的请求之前已被修改,因此您可能需要使用 422 响应,对于其他服务也是如此。有了这个,您可以确定您要处理的实体涉及其父级。
PD:对不起我的英语。
【讨论】:
以上是关于RESTful API URI 设计的主要内容,如果未能解决你的问题,请参考以下文章
RESTful URL 设计:公共与私有 API、分层 API 设计模式、URI 与 URL 设计?
架构师之路 — API 经济 — RESTful API 设计规范原则
RESTful API 设计 - 使用资源 URI 与 ID