RESTful API URI设计
我正在寻找有关RESTful API的URI设计的一些方向。我将有几个嵌套链接的资源,并且目前已经设计了与本文类似的URI: 下面的例子不是我正在构建的,但我认为它很好地说明了我的情况。(假设一个节目只能属于一个网络) 我的情况将与协会进一步发展两个层次,但所有协会都是一对多的。我正在考虑把它换成类似的东西:RESTful API URI设计,rest,uri,restful-url,restful-architecture,Rest,Uri,Restful Url,Restful Architecture,我正在寻找有关RESTful API的URI设计的一些方向。我将有几个嵌套链接的资源,并且目前已经设计了与本文类似的URI: 下面的例子不是我正在构建的,但我认为它很好地说明了我的情况。(假设一个节目只能属于一个网络) 我的情况将与协会进一步发展两个层次,但所有协会都是一对多的。我正在考虑把它换成类似的东西: /networks [GET,POST] /networks/{network_id} [GET,PUT] /networks/{network_id}/shows [GET,POST]
/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]
我的问题是:
第二个例子在我看来很好。URL描述了资源,并且使用了正确的HTTP谓词
如果有意义的话,让多个URL指向同一个资源是非常好的。但更重要的是,确保资源中包含连接节目与网络、剧集与节目等的元素。考虑到您在以下层次结构中有一对多关系:
network --> shows --> episodes
我认为第二种设计没有向服务器端提供足够的信息来处理您的请求。例如,如果您有以下数据:
Network id show_id episode_id
1 1 1
1 2 1
1 1 2
第一个详细的设计将在HTTP请求中提供足够的信息来获取数据:/networks/1/shows/1/scents/1
相反,第二种设计将具有:
/episodes/1
在第二种设计中,服务器端无法从数据中知道是指第1行还是第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]
URI是“可以指定名称的任何信息”
您的问题是一个与域相关的问题,只有了解您使用URI命名的资源的人才能真正回答您的问题
当你试图猜测你的域名时,我想到的问题是,“秀”真的依赖于“网络”吗
您的域中的网络是什么?节目和网络之间的关系是什么?是不是仅仅是某个人在播放这个节目?还是更多地与生产信息有关
我相信您的示例2更适合。我认为我们应该尽可能简单地保持RESTAPI URL e、 g 这里我以1.0版的XMLAPI为例。请记住在将来的更新中使用API的版本 您可以检查客户端请求的方法
e.g. tag
<method>getEpisodes</method>
例如标签
获得剧集
这里真正的问题是:您的第二个示例是否符合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"
}
}
}
现在,这只是带有IANA链接关系的HAL+JSON的测试版,但您也可以将JSON-LD与RDF词汇表(例如schema.org+hydra)一起使用。本例仅涉及层次结构(上一个、第一个、下一个、上一个、最后一个、集合、项目等),但您应该添加更多元数据,例如哪些链接指向网络、哪些链接指向节目、哪些链接指向插曲等。。。因此,您的客户将从元数据中了解内容,例如,他们可以使用链接自动导航。这就是REST的工作原理。因此URI结构对客户端来说并不重要。(如果你想让你的响应更紧凑,你可以使用紧凑型URI和URI模板。)
我认为第二个选项是可以的,但是如果你想验证关系,我会考虑第一个选项。例如,当您使用不同的网络获取一集时,这可能意味着该集在您的请求之前已被修改,因此您可能需要使用422进行响应,其他服务也是如此。这样,您就可以确保要处理的实体涉及其父实体
PD:对不起,我说的是英语。请记住,您最终决定了RESTful API的结构。是你的客户在使用它。我认为两者都是好的,尽管第一个显然更能说明网络、节目和剧集之间的层次关系。然而,如果URI变得异常长,那么分离出来让这些实体处于/之下也不是疯狂的。我会问你自己,什么样的资源实际上会被用得最多。如果是剧集和节目,那么将它们放在基础下就很有意义了。+1:我更喜欢
xlink:href
属性,但是
元素不是个坏主意。属性在XML/XHTML中工作得很好,但JSON等表示法不支持它们。无论如何,重要的是利用超媒体使服务真正RESTful。这看起来不是特别RESTful,而是非常SOAPy(如果这是您正在做的,这是可以的,但是SOAP和REST是构建应用程序的非常不同的方法…)我主要关心的是API的版本。e、 我的稳定API发布版本是1.2,我的客户在他们的应用程序中使用相同的版本。现在我们增强了API(版本
{
"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"
}
}
}