REST API可以至少以两种方式拥有参数:

作为url路径的一部分(即/api/resource/parametervalue) 作为查询参数(例如/api/resource?=参数值)

这里的最佳实践是什么?什么时候使用1,什么时候使用2,有什么一般的指导方针吗?

真实世界的例子:Twitter使用查询参数来指定间隔。(http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

把这些参数放在URL路径中会被认为是更好的设计吗?


当前回答

根据universe-resource-locator提供的“上下文”“打包”和POST数据,这对于定位器来说意味着#1。

注意第二条的局限性。比起第一条,我更喜欢post。

注:此处讨论的局限性

POST参数内容是否有最大大小?

GET请求的长度有限制吗?和最大大小的URL参数在_GET

附注:这些限制是基于客户端功能(浏览器)和服务器(配置)。

其他回答

根据universe-resource-locator提供的“上下文”“打包”和POST数据,这对于定位器来说意味着#1。

注意第二条的局限性。比起第一条,我更喜欢post。

注:此处讨论的局限性

POST参数内容是否有最大大小?

GET请求的长度有限制吗?和最大大小的URL参数在_GET

附注:这些限制是基于客户端功能(浏览器)和服务器(配置)。

这个主题的一个“维度”被忽略了,但它非常重要:有时“最佳实践”必须与我们正在实现或增强REST功能的平台相一致。

实际的例子:

现在许多web应用程序都实现了MVC(模型、视图、控制器)架构。他们假设提供了一个特定的标准路径,当那些web应用程序带有“启用SEO url”选项时更是如此。

这里只提一个相当有名的网络应用程序:OpenCart电子商务商店。 当管理员启用“SEO url”,它期望说url来一个相当标准的MVC格式,如:

http://www.domain.tld/special-offers/list-all?limit=25

在哪里

special-offers是处理URL的MVC控制器(显示special-offers页面) List-all是控制器要调用的动作或函数名。(*) Limit =25是一个选项,表示每页将显示25个项目。

(*) list-all是我使用的一个虚构的函数名。实际上,OpenCart和大多数MVC框架都有一个默认的、隐含的(通常在URL中省略)索引函数,当用户想要执行默认操作时,就会调用该索引函数。真实世界的URL是:

http://www.domain.tld/special-offers?limit=25

现在有了一个类似于上面的相当标准的应用程序或框架结构,你经常会得到一个针对它进行优化的web服务器,为它重写URL(真正的“非SEOed URL”应该是:http://www.domain.tld/index.php?route=special-offers/list-all&limit=25)。

因此,作为开发人员,你要面对的是处理现有的基础设施,并适应你的“最佳实践”,除非你是系统管理员,确切地知道如何调整Apache / NGinx重写配置(后者可能很讨厌!)等等。

因此,你的REST API通常会更好地遵循参考web应用程序的标准,无论是一致性还是易用性/速度(从而节省预算)。

回到上面的实际例子,一个一致的REST API应该是类似这样的url:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

或者(非SEO URLs)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

使用“路径形成”参数和“查询形成”参数的混合。

根据URI标准,路径用于层次参数,查询用于非层次参数。离岸金融中心。对你来说什么是等级制度是非常主观的。

在将多个uri分配给相同资源的情况下,我喜欢将用于标识的参数放入路径中,将用于构建表示的参数放入查询中。(对我来说,这种方式更容易路由。)

例如:

/users/123和/users/123?字段= "姓名、年龄" /users和/users?name = " John "年龄= 30

对于map reduce,我喜欢使用以下方法:

/用户?name = " John "年龄= 30 /用户/名称:约翰/年龄:30岁

因此,如何构造uri实际上取决于您(以及您的服务器端路由器)。

注意:只是提到这些参数是查询参数。因此,您真正要做的是定义一种简单的查询语言。对于复杂查询(包含与、或、大于等操作符),我建议您使用已经存在的查询语言。URI模板的功能非常有限…

如果有记录在案的最佳实践,我还没有找到它们。然而,当我决定在url中放置参数时,这里有一些指导原则:

可选参数往往更容易放在查询字符串中。

如果您希望在参数值与现有资源不对应时返回404错误,那么我倾向于使用路径段参数。例如:/customer/232,其中232不是有效的客户id。

然而,如果你想返回一个空列表,那么当参数没有找到时,我建议使用查询字符串参数。例如/联系人吗?name =戴夫

如果一个参数影响URI空间的整个子树,则使用路径段。例如,语言参数/en/document/foo.txt和/document/foo.txt?语言= en

我希望唯一标识符位于路径段中,而不是查询参数中。

uri的官方规则可以在这个RFC规范中找到。这里还有另一个非常有用的RFC规范,它定义了参数化uri的规则。

There are no hard and fast rules, but the rule of thumb from a purely conceptual standpoint that I like to use can briefly be summed up like this: a URI path (by definition) represents a resource and query parameters are essentially modifiers on that resource. So far that likely doesn't help... With a REST API you have the major methods of acting upon a single resource using GET, PUT, and DELETE . Therefore whether something should be represented in the path or as a parameter can be reduced to whether those methods make sense for the representation in question. Would you reasonably PUT something at that path and would it be semantically sound to do so? You could of course PUT something just about anywhere and bend the back-end to handle it, but you should be PUTing what amounts to a representation of the actual resource and not some needlessly contextualized version of it. For collections the same can be done with POST. If you wanted to add to a particular collection what would be a URL that makes sense to POST to.

这仍然留下了一些灰色区域,因为一些路径可以指向多少子代的父资源,这在某种程度上是自由裁量的,取决于他们的使用。这所画出的一条界限是,任何类型的传递表示都应该使用查询参数来完成,因为它不会有底层资源。

为了响应原始问题中给出的真实示例(Twitter的API),参数表示一个可传递查询,它过滤资源的状态(而不是层次结构)。在那个特定的例子中,向由这些约束表示的集合中添加数据是完全不合理的,而且该查询将无法表示为在对象图中有任何意义的路径。

The adoption of this type of resource oriented perspective can easily map directly to the object graph of your domain model and drive the logic of your API to the point where everything works very cleanly and in a fairly self-documenting way once it snaps into clarity. The concept can also be made clearer by stepping away from systems that use traditional URL routing mapped on to a normally ill-fitting data model (i.e. an RDBMS). Apache Sling would certainly be a good place to start. The concept of object traversal dispatch in a system like Zope also provides a clearer analog.