REST API Best practices: Where to put parameters?
REST API至少可以通过两种方式获取参数:
这里的最佳做法是什么? 是否有任何一般指导原则何时使用1以及何时使用2?
真实世界的例子:Twitter使用查询参数来指定间隔。(
将这些参数放在URL路径中会被认为是更好的设计吗?
如果有记录的最佳实践,我还没有找到它们。但是,这里有一些我在确定将参数放入url的位置时使用的指南:
可选参数往往更容易放入查询字符串中。
如果要在参数值与现有资源不对应时返回404错误,那么我会倾向于路径段参数。例如
但是如果你想返回一个空列表,那么当找不到参数时,我建议使用查询字符串参数。例如
如果参数影响URI空间的整个子树,则使用路径段。例如语言参数
我更喜欢将唯一标识符放在路径段而不是查询参数中。
URI的官方规则可在此RFC规范中找到。此处还有另一个非常有用的RFC规范,它定义了参数化URI的规则。
迟到的答案,但我会对已经分享的内容添加一些额外的见解,即请求有几种类型的"参数",你应该考虑到这一点。
现在让我们来看看这些参数可能出现的不同位置。
通常,您希望在标头或cookie中设置State,具体取决于它的状态信息类型。我想大家都同意这一点。如果需要,请使用自定义http标头(X-My-Header)。
类似地,Content只有一个位置,它位于请求体中,可以是查询字符串,也可以是http multipart和/或JSON内容。这与您向服务器发送内容时从服务器收到的内容一致。所以你不应该粗鲁,做不同的事情。
诸如"id = 5"或"action = refresh"或"page = 2"之类的定位器有意义作为URL路径,例如
过滤器始终位于查询字符串中,因为虽然它们是查找正确数据的一部分,但它们仅用于返回定位器单独返回的子集或修改。
如果"view"确定输出格式,那么它是一个过滤器(
请记住,缩小一组资源正在过滤。找到资源中特定的内容是找到... duh。子集过滤可以返回任意数量的结果(甚至为0)。定位将始终找到某个特定的实例(如果存在)。修改过滤将返回与定位器相同的数据,但修改后(如果允许这样的修改)。
希望这有助于给人们一些尤里卡时刻,如果他们已经迷失了关于放东西的地方!
这取决于设计。 REST over HTTP没有URI规则(主要的是它们是唯一的)。通常它涉及品味和直觉......
我采取以下方法:
- url path-element:资源及其path-element形成目录遍历和子资源(例如/ items / {id},/ users / items)。当不确定问你的同事时,如果他们认为遍历并且他们认为在"另一个目录"中最可能的路径元素是正确的选择
- url参数:当没有真正的遍历时(具有多个查询参数的搜索资源是一个非常好的例子)
IMO参数应该更好作为查询参数。 url用于标识资源,而添加的查询参数用于指定所需资源的哪个部分,资源应具有的任何状态等。
根据REST实现,
1)路径变量用于对资源的直接操作,如联系人或歌曲
恩..
GET etc / api / resource / {songid}或
GET etc / api / resource / {contactid}将返回相应的数据。
2)查询perms /参数用于直接资源,如歌曲的元数据
恩..,
GET / api / resource / {songid}?metadata = genres它将返回该特定歌曲的流派数据。
"打包"并根据universe-resource-locator提供的"上下文"POST您的数据,这意味着#1为定位器。
注意#2的局限性。我更喜欢POST到#1。
注意:讨论了限制
POST in POST参数内容是否有最大大小?
GET in GET请求的长度是否有限制?和_GET中URL参数的最大大小
附:这些限制基于客户端功能(浏览器)和服务器(配置)。
根据URI标准,路径用于分层参数,查询用于非分层参数。 OFC。对你来说,层次结构可能是非常主观的。
在将多个URI分配给同一资源的情况下,我喜欢将参数(识别所必需的)放入路径中,并将构建表示所需的参数放入查询中。 (对我来说这样更方便。)
例如:
-
/users/123 和/users/123?fields="name, age" -
/users 和/users?name="John"&age=30
对于map reduce我喜欢使用以下方法:
-
/users?name="John"&age=30 -
/users/name:John/age:30
因此,您(和您的服务器端路由器)如何构建您的URI真的取决于您。
注意:提到这些参数只是查询参数。所以你真正在做的是定义一个简单的查询语言。通过复杂的查询(包含像和,或大于等的运算符),我建议您使用现有的查询语言。 URI模板的功能非常有限......
这是我的意见。
查询参数用作请求的元数据。它们充当现有资源调用的过滤器或修改器。
例:
应该提供当天的日历活动。
如果您想要特定类别的活动
<5233>
或者如果您需要超过30分钟的活动
石蕊测试将检查是否仍可以在没有查询参数的情况下提供请求。
没有硬性和快速的规则,但是从我想要使用的纯概念观点来看,经验法则可以概括为:URI路径(根据定义)表示资源,查询参数本质上是该资源的修饰符。到目前为止,这可能没有帮助......使用REST API,您可以使用
这仍然留下一些灰色区域,因为一些路径可能指向父资源的子女的数量,这在某种程度上是自由裁量的并且取决于他们的使用。这绘制的一条硬线是任何类型的传递表示都应该使用查询参数来完成,因为它没有底层资源。
响应原始问题(Twitter的API)中给出的现实世界示例,参数表示过滤资源状态(而不是层次结构)的传递查询。在该特定示例中,添加到由那些约束表示的集合是完全不合理的,并且进一步该查询将不能被表示为在对象图的术语中有任何意义的路径。
采用这种面向资源的透视图可以轻松地直接映射到域模型的对象图,并将API的逻辑驱动到一切都非常干净的地方,并且一旦进入清晰度,就会以相当自我记录的方式。通过逐步使用映射到通常不合适的数据模型(即RDBMS)的传统URL路由的系统,也可以使概念更清楚。 Apache Sling肯定是一个很好的起点。在像Zope这样的系统中,对象遍历调度的概念也提供了更清晰的模拟。
作为程序员经常在客户端,我更喜欢查询参数。此外,对我来说,它将URL路径与参数分开,增加了清晰度,并提供了更多的可扩展性。它还允许我在URL / URI构建和参数构建器之间具有单独的逻辑。
如果涉及到某种树,我确实喜欢manuel aldana关于另一种选择的说法。我可以看到用户特定的部分就像这样。
这个主题的一个"维度"已被遗漏,但它非常重要:有时候"最佳实践"必须与我们正在实施的平台或扩展REST功能相结合。
实际例子:
现在许多Web应用程序都实现了MVC(模型,视图,控制器)架构。他们假设提供了某种标准路径,当这些Web应用程序带有"启用SEO URL"选项时更是如此。
只是提到一个相当着名的Web应用程序:一个OpenCart电子商务商店。
当管理员启用"SEO URL"时,它希望所述URL具有相当标准的MVC格式,如:
1 | http://www.domain.tld/special-offers/list-all?limit=25 |
哪里
-
special-offers 是处理URL的MVC控制器(显示特价商品页面) -
list-all 是要调用的控制器的操作或函数名称。 (*) -
limit = 25是一个选项,表示每页显示25个项目。
(*)
1 | http://www.domain.tld/special-offers?limit=25 |
使用现在相当标准的应用程序或类似于上面的框架结构,您通常会得到一个针对它进行优化的Web服务器,它会为其重写URL(真正的"非SEO URL"将是:
因此,作为开发人员,您将面临处理现有基础架构并调整"最佳实践"的问题,除非您是系统管理员,否则确切地知道如何调整Apache / NGinx重写配置(后者可能很讨厌!)等等上。
因此,您的REST API通常会更好地遵循引用Web应用程序的标准,既可以与其一致,又可以轻松/快速(从而节省预算)。
回到上面的实际例子,一致的REST API就像以下URL一样:
1 | http://www.domain.tld/api/special-offers-list?from=15&limit=25 |
或(非SEO网址)
1 | http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25 |
混合使用"路径形成"参数和"查询形成"参数。
我通常倾向于#2,作为查询参数(即/ api / resource?parameter = value)。
第三种选择是在body中实际发布参数=值。
这是因为它对多参数资源更有效,并且可以扩展以供将来使用。
无论你挑选哪一个,一定要选一个,不要混搭。这导致了令人困惑的API。
我看到很多REST API不能很好地处理参数。经常出现的一个例子是URI包括个人可识别信息。
我认为一个必然的问题是参数根本不应该是一个参数,而应该转移到请求的HEADER或BODY。
这是一个非常有趣的问题。
您可以同时使用它们,对此主题没有任何严格的规则,但使用URI路径变量有一些优点:
-
缓存:
Internet上的大多数Web缓存服务在包含查询参数时不会缓存GET请求。
他们这样做是因为有很多RPC系统使用GET请求来更改服务器中的数据(失败!!获取必须是一种安全的方法)
但是如果使用路径变量,则所有这些服务都可以缓存您的GET请求。
-
层次:
路径变量可以表示层次结构:
/城市/街道/广场
它为用户提供了有关数据结构的更多信息。
但是,如果您的数据没有任何层次结构关系,您仍然可以使用路径变量,使用逗号或分号:
/市/经度,纬度
作为一项规则,当参数的排序很重要时使用逗号,当排序无关紧要时使用分号:
/ IconGenerator /红色,蓝色,绿色
除了这些原因之外,在某些情况下,使用查询字符串变量非常常见:
- 当您需要浏览器自动将HTML表单变量放入URI时
- 当你处理算法时。例如,Google引擎使用查询字符串:
http:// www.google.com/search?q=rest
总而言之,没有任何强有力的理由使用其中一种方法,但只要可以,就使用URI变量。