返回也是集合的资源表示的最佳实践
Best practices for returning representation of resource that is also a collection
假设我想制作一个 RESTful 界面,并且我想根据它们的 ID 使用 foo
。这里没有新内容:
GET /api/foo1
return 是 foo1
. 的表示(例如使用 JSON)
DELETE /api/foo1
删除 foo1
.
等等
现在让我告诉你,"foo" 是一个集合类型的东西。所以我希望能够将 "bar" 添加到 "foo":
PUT /api/foo1/bar3
将 bar3
添加到 foo1
。
GET /api/foo1/bar3
return 表示 foo1
。
DELETE /api/foo1/bar3
从 foo1
. 中删除 bar3
DELETE /api/foo1
一共删除 foo1
。
现在问题仍然存在:GET /api/foo1
是做什么的?它只是 return foo1
的表示,就像我最初在这个问题中假设的那样吗?还是 return 一个柱列表?还是 return foo1
的表示既是 foo1
的描述又 包含 所有包含的柱的列表?
或者 GET /api/foo1
应该只是 return 我一开始假设的 foo1
的表示,并且需要 PROPFIND
请求列出 [=12] 内的柱=](WebDAV 采取的方法)?但是为了保持一致,难道我不必将所有其他列表类型功能更改为 PROPFIND
,直接与所有那些说使用 GET /api/foo1
的 RESTful 教程相矛盾列出内容?
webdav 的语义从未真正与 RESTful 接口的习语相协调。
理论上,GET 应该检索资源状态的表示,而 PROPFIND 应该用于检索集合的成员。
所以你应该这样做:
- GET /api/foo1/ - return仅 foo1 的状态
- PROPFIND /api/foo1/ - returnfoo1
的成员
如果您告诉大多数前端开发人员使用 PROPFIND,他们会吓坏的,尽管它在浏览器 js 实现中完全受支持。
我个人使用 webdav/json 网关,其中使用 RESTful 习语发出请求,但路由到我的 webdav 实现
例如我会这样做:
GET /api/foo1/_PROPFIND?fields=name,fooProp1,fooProp2
那会 return
[
{ name : "bar1", fooProp1: "..", fooProp2 : ".."},
{ name : "bar2", fooProp1: "..", fooProp2 : ".."}
]
此方法的一个优点是客户端可以控制 json 属性 returned。这很好,因为富人 API 会有很多属性,但在大多数情况下,客户不需要所有属性。
RESTfull API中的路由及其操作完全由开发人员设计。开发人员在请求特定路线时决定 return 的内容,比如 GET /api/foo1
.
并且开发人员应该设计包括/api/foo1/bar
在内的每条路线。没有关于特定路线应该做什么的具体规则。如果您的 API 是一个开源项目,请对每条路线进行清晰明了的记录。
不要浪费时间思考老派策略。
经过一番思考,我认为从 RESTful 的角度最好的概念性解释是,通常 "thing" 与其 "collection" 不是一回事。因此,虽然在 WebDAV 世界中,directory/
可能与保存其文件的东西相同,但在 RESTful 世界中,我可能有一个单独的 directory/files/
子路径用于包含的文件。这样我就可以从保存的文件中单独操作目录。
考虑一个包含谷仓的农场 RESTful API。端点 farm/api/barns/
可能 return 一个谷仓列表,其中之一是 farm/api/barns/bigredbarn
。我天真地认为检索 farm/api/barns/bigredbarn/
会为我提供谷仓中的动物列表,这就是引发这个问题的原因。
但实际上谷仓里的动物只是大红谷仓的一方面。它可能包含车辆和干草:
farm/api/barns/bigredbarn/animals/
farm/api/barns/bigredbarn/vehicles/
farm/api/barns/bigredbarn/haybales/
采用这种方法,我所面临的困境就不会出现。
假设我想制作一个 RESTful 界面,并且我想根据它们的 ID 使用 foo
。这里没有新内容:
GET /api/foo1
return 是foo1
. 的表示(例如使用 JSON)
DELETE /api/foo1
删除foo1
.
等等
现在让我告诉你,"foo" 是一个集合类型的东西。所以我希望能够将 "bar" 添加到 "foo":
PUT /api/foo1/bar3
将bar3
添加到foo1
。GET /api/foo1/bar3
return 表示foo1
。DELETE /api/foo1/bar3
从foo1
. 中删除 DELETE /api/foo1
一共删除foo1
。
bar3
现在问题仍然存在:GET /api/foo1
是做什么的?它只是 return foo1
的表示,就像我最初在这个问题中假设的那样吗?还是 return 一个柱列表?还是 return foo1
的表示既是 foo1
的描述又 包含 所有包含的柱的列表?
或者 GET /api/foo1
应该只是 return 我一开始假设的 foo1
的表示,并且需要 PROPFIND
请求列出 [=12] 内的柱=](WebDAV 采取的方法)?但是为了保持一致,难道我不必将所有其他列表类型功能更改为 PROPFIND
,直接与所有那些说使用 GET /api/foo1
的 RESTful 教程相矛盾列出内容?
webdav 的语义从未真正与 RESTful 接口的习语相协调。
理论上,GET 应该检索资源状态的表示,而 PROPFIND 应该用于检索集合的成员。
所以你应该这样做:
- GET /api/foo1/ - return仅 foo1 的状态
- PROPFIND /api/foo1/ - returnfoo1 的成员
如果您告诉大多数前端开发人员使用 PROPFIND,他们会吓坏的,尽管它在浏览器 js 实现中完全受支持。
我个人使用 webdav/json 网关,其中使用 RESTful 习语发出请求,但路由到我的 webdav 实现
例如我会这样做:
GET /api/foo1/_PROPFIND?fields=name,fooProp1,fooProp2
那会 return
[
{ name : "bar1", fooProp1: "..", fooProp2 : ".."},
{ name : "bar2", fooProp1: "..", fooProp2 : ".."}
]
此方法的一个优点是客户端可以控制 json 属性 returned。这很好,因为富人 API 会有很多属性,但在大多数情况下,客户不需要所有属性。
RESTfull API中的路由及其操作完全由开发人员设计。开发人员在请求特定路线时决定 return 的内容,比如 GET /api/foo1
.
并且开发人员应该设计包括/api/foo1/bar
在内的每条路线。没有关于特定路线应该做什么的具体规则。如果您的 API 是一个开源项目,请对每条路线进行清晰明了的记录。
不要浪费时间思考老派策略。
经过一番思考,我认为从 RESTful 的角度最好的概念性解释是,通常 "thing" 与其 "collection" 不是一回事。因此,虽然在 WebDAV 世界中,directory/
可能与保存其文件的东西相同,但在 RESTful 世界中,我可能有一个单独的 directory/files/
子路径用于包含的文件。这样我就可以从保存的文件中单独操作目录。
考虑一个包含谷仓的农场 RESTful API。端点 farm/api/barns/
可能 return 一个谷仓列表,其中之一是 farm/api/barns/bigredbarn
。我天真地认为检索 farm/api/barns/bigredbarn/
会为我提供谷仓中的动物列表,这就是引发这个问题的原因。
但实际上谷仓里的动物只是大红谷仓的一方面。它可能包含车辆和干草:
farm/api/barns/bigredbarn/animals/
farm/api/barns/bigredbarn/vehicles/
farm/api/barns/bigredbarn/haybales/
采用这种方法,我所面临的困境就不会出现。