【问题标题】:RESTful API design debate: complex query for restful endpointRESTful API 设计辩论:RESTful 端点的复杂查询
【发布时间】:2014-12-25 19:19:41
【问题描述】:

我正在为大量报告数据设计一个 RESTful api,我想传递一组复杂的参数,如下面的代码块所示。我正在为这个端点使用 POST 和 GET 进行辩论。团队成员似乎更喜欢 GET,但我不确定将这些数据量作为 GET 参数传递的最佳方式,目前最好的想法是使用一个名为 jsonparams 之类的 GET 参数,该参数将具有以下所有 json 编码

{
  "filters": 
    [
      {
        "field": "metric-name",
        "gt": (float/int),
        "lt": (float/int)
      },
      {
        "field": "metric-name-2",
        "gt": (float/int),
        "lt": (float/int)
      }
    ],
  "sort": 
    [
      {
        "field": "metic-name",
        "order": "ASC"/"DESC"
      },
      {
        "field": "metic-name-2",
        "order": "ASC"/"DESC"
      }
    ]
  "limit": 100,
  "offset": 0
}

【问题讨论】:

标签: rest restful-architecture


【解决方案1】:

如果您要将数据添加到资源或创建资源,请使用 POST。 GET 是获取一个已经存在的资源,而不是改变资源的状态。

更新:虽然POST 请求可以更新资源,但如果该操作是幂等的(这意味着不会导致创建新资源,并且每次使用相同的参数和数据发出请求时,您可以保证相同结果资源),那么建议使用PUT。如果它不是幂等的,但您没有替换整个资源,如果只更新部分资源,请使用PATCH

如果参数与疯狂的基于序列化 GET 参数的请求一起使用以实现某种感知的简单性,那么您将不会听从 REST。

现在,如果您只检索资源(不创建),请使用 GET。虽然我更喜欢人类可键入的参数,但这不是必需的。如果您的情况是 100% 检索,您可以将整个集合编码成一个巨大的编码参数字符串,但我建议至少将其拆分一下以提高理智,方法是:

 /resource?filters=urlencoded_filter_array&sort=urlencoded_sort_array&offset=0&count=100

或者你可以更明确地说:

 /resource?filter1=urlencoded_filter_json&filter2=urlencoded_filter_json .... sort2=urlencoded_sort_json&offset=0&count=100

或者最后(我最喜欢的)一组完全明确的分解参数

 /resource?filter1_field=bah&filter1_gt=1.0&filter1_lt<2&filter2_field=boo&filter2_lt...

我喜欢最后一个,因为没有对 json 进行编码/解码,然后对整个 json 字符串进行 url 编码。这种格式很容易在访问日志和故障排除中破译。它也非常可缓存,即使参数顺序发生变化,一些代理缓存仍然可以使用它,而在 json 对象中编码一些过滤器,如果它们被移动,就代理而言,它们看起来像完全不同的值.对我来说,它是对 REST 最友好的(如果这有意义的话),尽管前两个示例是很好的 REST GET 请求。

解析参数名称的额外工作并没有那么大惊小怪。一种简单的方法可以将您的 json 转换为参数字符串,而另一种简单的方法可以从显式 filter1_xyz 格式重新水化 json 对象。

【讨论】:

  • 如上例所示,您对复杂参数的解决方案是什么?
  • @dismal 如果您正在创建资源,则可以将 json 对象作为帖子正文传递。
  • @dismal 看到我更新的答案。如果您不更改任何内容,只是过滤结果,则可以使用 get。
【解决方案2】:

POST 是用于未由 HTTP 标准化的任何操作的方法。检索由 GET 方法标准化,因此使用 POST 检索与潜在资源对应的信息绝不是 RESTful。理论上,你应该使用 GET,不管你的 URI 有多么复杂。

但是,由于您正在执行的查询没有可以执行 GET 的单一资源,因此使用 POST 似乎很好,只要您知道缺点并且您的文档清晰关于它。坦率地说,我认为使用 POST 比将该有效负载编码为 JSON + base64 并将其作为查询字符串发送只是为了纯粹而清晰得多。

使用 POST 的真正问题在于,人们使用它时会避免或阻止使用真实的 URI。在您的情况下,这似乎不是问题,因为您有一个有效的集合 URI,但是查询的语义太复杂而无法轻松表达。

如果您决定使用 GET,则有一个问题。虽然 HTTP 规范对 URI 没有限制,但大多数实现都会这样做,如果您需要将所有这些参数作为查询字符串提供,您可能会达到该限制。在这种情况下,绕过底层实现的限制是 RESTful 的,只要它与您的应用程序分离。做你想做的事情的惯例是使用 POST 方法和上面描述的有效负载,以及 X-HTTP-Method-Override: GET 标头。

【讨论】:

  • 我将像 Ray 的回答一样使用 GET,希望我不会遇到任何 URI 限制!
  • 正如我所说,理论上这是正确的方法。如果它被采用是因为它适用于您的情况,而不仅仅是为了纯粹,我完全赞成。
猜你喜欢
  • 2016-09-07
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
相关资源
最近更新 更多