REST API最佳实践:在何处放置参数?

时间:2010-10-26 13:45:42

标签: api rest url

REST API至少可以通过两种方式获取参数:

  1. 作为网址路径的一部分(即/api/resource/parametervalue
  2. 作为查询参数(即/api/resource?parameter=value
  3. 这里的最佳做法是什么?是否有任何一般指导原则何时使用1以及何时使用2?

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

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

14 个答案:

答案 0 :(得分:254)

如果有记录的最佳做法,我还没有找到它们。但是,这里有一些我在确定将参数放在URL中的位置时使用的指南:

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

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

如果你想返回一个空列表,那么当找不到参数时,我建议使用查询字符串参数。例如/contacts?name=dave

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

我更喜欢将唯一标识符放在路径段而不是查询参数中。

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

答案 1 :(得分:152)

迟到的答案,但我会对已经分享的内容添加一些额外的见解,即请求中有几种类型的“参数”,您应该考虑到这一点。

  1. 定位器 - 例如资源标识符,例如ID或action / view
  2. 过滤器 - 例如提供搜索,排序或缩小结果集的参数。
  3. 国家 - 例如会话识别,api密钥,whatevs。
  4. 内容 - 例如要存储的数据。
  5. 现在让我们看一下这些参数可能出现的不同地方。

    1. 请求标题&饼干
    2. 网址查询字符串(“GET”vars)
    3. 网址路径
    4. 正文查询字符串/多部分(“POST”变种)
    5. 通常,您希望在标头或Cookie中设置State,具体取决于状态信息的类型。我想大家都同意这一点。如果需要,请使用自定义http标头(X-My-Header)。

      类似地,Content只有一个位置,它位于请求体中,可以是查询字符串,也可以是http multipart和/或JSON内容。这与您向服务器发送内容时从服务器收到的内容一致。所以你不应该粗鲁,做不同的事情。

      诸如“id = 5”或“action = refresh”或“page = 2”之类的定位器有意义作为URL路径,例如mysite.com/article/5/page=2部分你知道每个部分应该是什么mean(文章和5等基础知识显然意味着获取id为5的类型文章的数据),并将其他参数指定为URI的一部分。如果您知道在URI中的某个点之后“文件夹”是成对的键值,它们可以采用page=2page/2的形式。

      过滤器总是放在查询字符串中,因为虽然它们是查找正确数据的一部分,但它们仅用于返回定位器单独返回的子集或修改。 mysite.com/article/?query=Obama(子集)中的搜索是过滤器,/article/5?order=backwards(修改)也是如此。想想它的作用,而不仅仅是它的名称!

      如果“view”确定输出格式,那么它是一个过滤器(mysite.com/article/5?view=pdf),因为它返回找到的资源的修改,而不是归巢于我们想要的资源。如果它决定我们看到的文章的哪个特定部分(mysite.com/article/5/view=summary),那么它就是一个定位器。

      请记住,缩小一组资源正在过滤。找到资源中特定的内容是找到... duh。子集过滤可以返回任意数量的结果(甚至为0)。定位将始终找到某个特定的实例(如果存在)。修改过滤将返回与定位器相同的数据,但修改后(如果允许这样的修改)。

      希望这有助于给人们一些尤里卡时刻,如果他们已经迷失在哪里放东西!

答案 2 :(得分:21)

这取决于设计。 REST over HTTP没有URI规则(主要的是它们是唯一的)。通常它涉及品味和直觉......

我采取以下方法:

  • url path-element:资源及其path-element形成目录遍历和子资源(例如/ items / {id},/ users / items)。当不确定问你的同事时,如果他们认为遍历并且他们认为在“另一个目录”中最可能的路径元素是正确的选择
  • url参数:当没有真正的遍历时(带有多个查询参数的搜索资源就是一个非常好的例子)

答案 3 :(得分:18)

IMO参数应该更好作为查询参数。 url用于标识资源,而添加的查询参数用于指定所需资源的哪个部分,资源应具有的任何状态等。

答案 4 :(得分:17)

根据REST实施,

1)路径变量用于对资源的直接操作,如联系人或歌曲     恩..
    GET etc / api / resource / {songid}或
    GET etc / api / resource / {contactid}将返回相应的数据。

2)查询perms / argument 用于直接资源,如歌曲的元数据     恩..,     GET / api / resource / {songid}?metadata = genres它将返回该特定歌曲的流派数据。

答案 5 :(得分:16)

“打包”并根据universe-resource-locator提供的“上下文”对您的数据进行POST,这意味着定位符为#1。

注意#2的局限性。我更喜欢POST到#1。

注意:讨论了

的限制

Is there a max size for POST parameter content?

中发帖

Is there a limit to the length of a GET request?Max size of URL parameters in _GET

中获取

P.S。这些限制基于客户端功能(浏览器)和服务器(配置)。

答案 6 :(得分:5)

根据URI standard,路径用于分层参数,查询用于非分层参数。 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 templates的功能非常有限......

答案 7 :(得分:4)

作为程序员经常在客户端,我更喜欢查询参数。此外,对我来说,它将URL路径与参数分开,增加了清晰度,并提供了更多的可扩展性。它还允许我在URL / URI构建和参数构建器之间具有单独的逻辑。

如果涉及某种树,我确实喜欢manuel aldana关于另一种选择的说法。我可以看到用户特定的部分就像这样。

答案 8 :(得分:4)

没有严格的规则,但从我想要使用的纯粹概念角度来看,经验法则可以简单地总结如下:URI路径(根据定义)表示资源,查询参数本质上是修饰符在那资源上。到目前为止,这可能没有帮助......使用REST API,您可以使用GETPUTDELETE来处理单个资源的主要方法。因此,是否应该在路径中表示某些内容或作为参数可以减少这些方法是否对所讨论的表示有意义。你会合理PUT在那条道路上有什么东西,这样做会在语义上合理吗?你当然可以在任何地方PUT使用并弯曲后端来处理它,但是你应该PUT相当于实际资源的代表而不是它的一些不必要的上下文版本。对于集合,可以使用POST完成相同的操作。如果您想要添加到特定的集合,那么对POST to。

有意义的网址

这仍然留下一些灰色区域,因为一些路径可能指向父资源的子女的数量,这在某种程度上是自由裁量的并且取决于他们的使用。这绘制的一条硬线是任何类型的传递表示都应该使用查询参数来完成,因为它没有底层资源。

为了回应原始问题(Twitter的API)中给出的真实世界示例,参数表示过滤资源状态(而不是层次结构)的传递查询。在该特定示例中,添加到由这些约束表示的集合是完全不合理的,并且该查询将不能被表示为在对象图的术语中有任何意义的路径。

采用这种面向资源的透视图可以轻松地直接映射到域模型的对象图,并将API的逻辑驱动到一切都非常干净的地方,并且一旦捕获它就会以相当自我记录的方式变得清晰。通过逐步使用映射到通常不合适的数据模型(即RDBMS)的传统URL路由的系统,也可以使概念更清楚。 Apache Sling肯定是一个很好的起点。像Zope这样的系统中对象遍历调度的概念也提供了更清晰的模拟。

答案 9 :(得分:4)

这是我的意见。

查询参数用作请求的元数据。它们充当现有资源调用的过滤器或修改器。

示例:

/calendar/2014-08-08/events

应该提供当天的日历活动。

如果您想要特定类别的活动

/calendar/2014-08-08/events?category=appointments

或者如果您需要超过30分钟的活动

/calendar/2014-08-08/events?duration=30

一个试金石是检查是否仍可以在没有查询参数的情况下提供请求。

答案 10 :(得分:2)

我通常倾向于#2,作为查询参数(即/ api / resource?parameter = value)。

第三种选择是在body中实际发布参数=值。

这是因为它对多参数资源更有效,并且可以扩展以供将来使用。

无论你挑选哪一个,一定要选一个,不要混搭。这会导致令人困惑的API。

答案 11 :(得分:2)

一个"维度"这个话题被遗漏了但它非常重要:有时候,最佳实践"必须与我们正在实施的平台或使用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控制器(显示特价商品页面)

  • list-all是要调用的控制器操作或函数名称。 (*)

  • limit = 25是一个选项,说明每页将显示25个项目。

(*)list-all是我为清晰起见而使用的虚函数名。实际上,OpenCart和大多数MVC框架都有一个默认的暗示(通常在URL中省略)index函数,当用户想要执行默认操作时会调用该函数。所以现实世界的URL将是:

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

使用与上述类似的现在相当标准的应用程序或框架结构,您经常会得到一个针对它进行优化的Web服务器,它会为其重写URL(真正的"非SEOed URL&#34) ;将是:http://www.domain.tld/index.php?route=special-offers/list-all&limit=25)。

因此,作为开发人员,您将面临处理现有基础架构并调整您的最佳实践的问题,除非您是系统管理员,否则请确切知道如何调整Apache / NGinx重写配置(后者可能很讨厌!)等等。

因此,您的REST API通常会更好地遵循引用的Web应用程序的标准,既可以与其一致,又可以轻松/快速(从而节省预算)。

回到上面的实际例子,一致的REST API将是以下网址:

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

或(非SEO网址)

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

混合了#34;路径形成"参数和"查询形成"参数。

答案 12 :(得分:1)

我看到很多REST API无法很好地处理参数。经常出现的一个例子是URI包括个人可识别信息。

http://software.danielwatrous.com/design-principles-for-rest-apis/

我认为一个必然的问题是参数根本不应该是一个参数,而应该转移到请求的 HEADER BODY

答案 13 :(得分:0)

这是一个非常有趣的问题。

您可以同时使用它们,但没有关于此主题的任何严格规则,但使用URI路径变量有一些优点:

  • 缓存: 互联网上的大多数Web缓存服务在包含查询参数时不会缓存GET请求。 他们这样做是因为有很多RPC系统使用GET请求来更改服务器中的数据(失败!!获取必须是一种安全的方法)

但是如果你使用路径变量,所有这些服务都可以缓存你的GET请求。

  • 层次: 路径变量可以表示层次结构: /城市/街道/地点

它为用户提供了有关数据结构的更多信息。

但是如果您的数据没有任何层次结构关系,您仍然可以使用路径变量,使用逗号或分号:

/城市/经度,纬度

通常,当参数的排序很重要时使用逗号,当排序不重要时使用分号:

/ IconGenerator /红色;蓝色;绿色

除了这些原因之外,在某些情况下,使用查询字符串变量非常常见:

  • 当您需要浏览器自动将HTML表单变量放入URI
  • 当您处理算法时。例如,Google引擎使用查询字符串:

http:// www.google.com/search?q=rest

总而言之,没有任何强有力的理由使用其中一种方法,但只要有可能,请使用URI变量。