同一资源的不同RESTful表示
我的应用程序的资源位于同一资源的不同RESTful表示,rest,http,url,web-applications,restapi,Rest,Http,Url,Web Applications,Restapi,我的应用程序的资源位于/foo。通常,它由HTTP响应负载表示,如下所示: {"a": "some text", "b": "some text", "c": "some text", "d": "some text"} 客户端并不总是需要此对象的所有四个成员。客户机用什么RESTfully语义方法告诉服务器它在表示中需要什么?e、 g.如果需要: {"a": "some text", "b": "some text", "d": "some text"} 它应该如何获取它?一些可能性(如果
/foo
。通常,它由HTTP响应负载表示,如下所示:
{"a": "some text", "b": "some text", "c": "some text", "d": "some text"}
客户端并不总是需要此对象的所有四个成员。客户机用什么RESTfully语义方法告诉服务器它在表示中需要什么?e、 g.如果需要:
{"a": "some text", "b": "some text", "d": "some text"}
它应该如何获取它?一些可能性(如果我误解了REST,我正在寻找更正):
GET/foo?sections=a、b、d
。
- 查询字符串(毕竟称为查询字符串)的意思似乎是“查找与此条件匹配的资源并告诉我它们的情况”,而不是“根据此定制向我表示此资源”
GET/foo/a+b+d
我最喜欢的如果REST语义没有涵盖这个问题,因为它很简单。
- 破坏URI不透明度,违反HATEOAS
- 似乎打破了资源(URI的唯一含义是标识一个资源)和表示之间的区别。但这是有争议的,因为它与表示可呈现的
/widget/
资源列表的/widget/
一致,我从来没有遇到过问题
- 放松我的限制,响应
GET/foo/a
等,让客户机根据它想要的/foo
组件发出请求。
- 增加开销,如果
/foo
有数百个组件,而客户端需要其中的100个,这可能会成为一场噩梦
- 如果我想支持
/foo
的HTML表示,我必须使用Ajax,如果我只想要一个可以被爬网、由极简浏览器呈现的HTML页面,这是有问题的
- 为了维护HATEOAS,它还要求指向这些“子资源”的链接存在于其他表示中,可能位于
/foo
:{“a”:{“url”:/foo/a”,“content”:“some text”},…}
- 请求正文中的
GET/foo
,内容类型:application/json
和{“sections”:[“a”、“b”、“d”]}
。
- 不可标记和不可缓存
- HTTP没有为
GET
定义正文语义。这是合法的HTTP,但我如何保证某些用户的代理不会从GET
请求中删除主体
- 我不允许我在
GET
请求中添加主体,因此我不能将其用于测试
- 自定义HTTP头:
需要的部分:A、b、d
- 如果可能的话,我宁愿避免使用自定义标题
- 不可标记和不可缓存
POST/foo/requests
,内容类型:application/json
和{“sections”:[“a”、“b”、“d”]}
,在请求正文中。接收带有位置:/foo/requests/1的201
。然后GET/foo/requests/1
接收所需的/foo
- 笨重的;需要来回和一些奇怪的代码
- 取消标记和取消缓存,因为
/foo/requests/1
只是一个别名,只能使用一次,并且只能保留到被请求为止
如果a、b、c是像admin for role属性这样的资源的属性,那么正确的方法是使用您建议的第一种方法GET/foo?sections=a、b、d
,因为在这种情况下,您将对foo
集合应用过滤器。否则,如果a、b和c是foo
集合的单个资源,则接下来的方法是执行一系列GET
请求/foo/a/foo/b/foo/c
。正如您所说,这种方法的请求有效负载很高,但它是遵循Restfull方法的正确方法。我不会使用第二个提议因为url中的加号字符有特殊的含义
另一个建议是放弃使用GET和POST,为foo
集合创建一个动作,例如:/foo/filter
或/foo/selection
或表示集合上动作的任何动词。通过这种方式,拥有一个post请求主体,您可以传递一个json资源列表。我建议使用querystring解决方案(您的第一个)。你反对其他选择的论点是很好的论点(我在实践中遇到过这些论点,试图解决同样的问题)。特别是,“放松约束/响应foo/a
”解决方案可以在有限的情况下工作,但在实现和使用方面给API带来了很多复杂性,根据我的经验,不值得为此付出努力
我将用一个常见的例子来弱化你的“似乎意味着”的论点:考虑一个大对象列表的资源(<代码>获取/客户< /代码>)。对这些对象进行分页是完全合理的,使用querystring进行分页是很常见的:
GET/Customers?offset=100&take=50
。在这种情况下,querystring不会对列出的对象的任何属性进行过滤,而是为该对象的子视图提供参数
更具体地说,我要说的是,您可以通过以下使用查询字符串的标准来保持一致性和HATEOAS:
- 返回的对象应与从Url返回的对象(不带querystring)相同
- 没有querystring的Uri应该返回完整的对象-具有相同Uri的querystring的任何视图的超集。因此,如果缓存未修饰Uri的结果,就知道拥有完整的实体
- 为给定querystring返回的结果应该是确定性的,因此具有querystring的uri很容易缓存
但是,这些URI的回报有时会带来更复杂的问题:
- 为仅因查询字符串不同的URI返回不同的实体类型可能是不可取的(
/foo
是一个实体,但{
"id": 5,
"name": "John",
"surename": "Doe",
"marital_status": "single",
"sex": "male",
...
}
/customers/5?fields=name,surename
{
"name": "John",
"surename": "Doe"
}