REST API最佳实践:在哪里放置参数?
REST API至less可以有两种参数:
- 作为URLpath的一部分 (即
/api/resource/parametervalue
) - 作为查询参数 (即
/api/resource?parameter=value
)
这里最好的做法是什么? 有什么一般的准则什么时候使用1,什么时候使用2?
真实世界的例子:Twitter使用查询参数来指定时间间隔。 ( http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321
)
将这些参数放在URLpath中会被认为是更好的devise吗?
如果有logging的最佳做法,我还没有find他们。 不过,在确定将参数放入url的位置时,以下是一些指南:
可选参数往往更容易放在查询string中。
如果你想返回一个404错误,当参数值不对应一个现有的资源,那么我会倾向于一个path段参数。 例如/customer/232
,其中232不是有效的客户ID。
但是如果你想返回一个空的列表,那么当参数没有find时,我build议使用查询string参数。 例如/contacts?name=dave
如果参数影响URI空间的整个子树,则使用path段。 例如语言参数/en/document/foo.txt
与/document/foo.txt?language=en
我更喜欢唯一标识符在path段而不是查询参数。
URI的官方规则可在此RFC规范中find 。 这里还有另一个非常有用的RFC规范,它定义了参数化URI的规则。
迟到的答案,但我会添加一些额外的见解分享,即有几种types的“参数”的请求,你应该考虑到这一点。
- 定位器 – 例如资源标识符,如ID或动作/视图
- filter – 例如提供search,sorting或缩小结果集的参数。
- 状态 – 例如会话标识,api密钥,whatevs。
- 内容 – 例如要存储的数据。
现在让我们看看这些参数可以去的地方。
- 请求标头和Cookie
- url查询string(“GET”vars)
- urlpath
- Body query string / multipart(“POST”vars)
一般来说,您希望状态设置在标题或Cookie中,具体取决于它是哪种types的状态信息。 我想我们都可以同意这一点。 如果需要的话,使用自定义的http头(X-My-Header)。
同样,内容只有一个位于请求正文中的位置,可以是查询string,也可以是http multipart和/或JSON内容。 这与您发送内容时从服务器收到的内容一致。 所以你不应该粗鲁,做不同的事情。
诸如“id = 5”或“action = refresh”或“page = 2”之类的定位符将具有URLpath的意义,例如mysite.com/article/5/page=2
,其中部分地知道每个部分应该是指(基本上如文章和5显然意味着让我的types文章的数据与id 5)和额外的参数被指定为URI的一部分。 如果您知道在URI中的某个点之后“folders”是配对的键值,则它们可以是page=2
或page/2
的forms。
filter总是进入查询string,因为虽然它们是查找正确数据的一部分,但它们只是返回Locators返回的子集或修改。 mysite.com/article/?query=Obama
(子集)中的search是一个filter,所以/article/5?order=backwards
(修改)。 想想它是怎么做的,而不仅仅是它叫什么!
如果“查看”确定输出格式,那么它是一个filter( mysite.com/article/5?view=pdf
),因为它返回一个find的资源的修改,而不是回到我们想要的资源上。 如果它决定文章的哪一部分我们可以看到( mysite.com/article/5/view=summary
),那么它是一个定位器。
请记住,缩小一组资源是过滤。 在一个资源中find特定的东西是定位…呃。 子集过滤可能会返回任意数量的结果(甚至是0)。 定位将总是find某个特定的实例(如果存在的话)。 修改过滤将返回与定位符相同的数据,除了修改(如果允许这样的修改)。
希望这有助于给人们一些尤里卡的时刻,如果他们已经失去了把东西放在哪里!
这取决于一个devise。 HTTP上的REST没有URI的规则(主要是它们是唯一的)。 往往涉及到品味和直觉的问题。
我采取以下方法:
- url path-element:资源及其path元素形成目录遍历和子资源(例如/ items / {id},/ users / items)。 如果不确定询问你的同事,如果他们认为遍历,他们认为在“另一个目录”中最有可能的path元素是正确的select
- url参数:当没有真正的遍历(具有多个查询参数的search资源是一个非常好的例子)
IMO的参数应该更好的查询参数。 url用于标识资源,而添加的查询参数用于指定所需资源的哪一部分,资源应具有的任何状态等。
根据REST实施,
1) pathvariables用于对资源进行直接操作,如联系人或歌曲等。
GET etc / api / resource / {songid}或者
GET etc / api / resource / {contactid}将返回相应的数据。
2) 查询权限/参数用于诸如歌曲的元数据的直接资源,GET / api / resource / {songid}?metadata =stream派,它将返回该特定歌曲的stream派数据。
“打包”并将数据发送到universe-resource-locator提供的“上下文”,这意味着#1为了定位器。
注意#2的局限性。 我更喜欢POST到#1。
注意:限制是讨论的
POST in 是否有POST参数内容的最大大小?
GET GET请求的长度是否有限制? 和_GET中的最大URL参数大小
ps这些限制是基于客户端function(浏览器)和服务器(configuration)。
根据URI标准 ,path是针对分层参数的,而查询是针对非分层参数的。 OFC。 对于你来说什么是分层的可能是非常主观的。
在多个URI被分配给相同资源的情况下,我喜欢将参数(对于识别是必需的)放入查询中所需的path和参数中。 (对我来说,这是更容易路由。)
例如:
-
/users/123
和/users/123?fields="name, age"
-
/users
和/users?name="John"&age=30
对于地图减less我喜欢使用以下方法:
-
/users?name="John"&age=30
-
/users/name:John/age:30
所以真正取决于你(和你的服务器端路由器)如何构build你的URI。
注意:只要提到这些参数是查询参数。 所以你真正在做的是定义一个简单的查询语言。 通过复杂的查询(包含运算符,比如,或者大于等),我build议您使用已经存在的查询语言。 URI模板的function非常有限…
作为一个经常在客户端的程序员,我更喜欢查询参数。 另外,对我来说,它将URLpath从参数中分离出来,增加了清晰度,并提供了更多的可扩展性。 它还允许我在URL / URI构build和参数构build器之间有单独的逻辑。
我喜欢manuel aldana所说的另一种select,如果涉及某种树木的话。 我可以看到像这样的用户特定的部分。
没有硬性和快速的规则,但从我纯粹的概念angular度来看,我喜欢使用的经验法则可以简单地归纳如下:URIpath(根据定义)表示资源,查询参数本质上是该资源上的修饰符。 到目前为止,这可能不会有帮助…使用REST API,您可以使用GET
, PUT
和DELETE
对单个资源进行操作。 因此,无论是在path中还是在参数中表示,都可以归结为这些方法是否对所讨论的表示有意义。 你会合理地把东西放在那条路上,这样做在语义上是合理的吗? 你当然可以把任何东西放在任何地方,并弯曲后端来处理它,但是你应该把实际资源的表示放在一边,而不是一些不必要的情景化版本。 对于集合,可以使用POST
完成相同的操作。 如果你想添加一个特定的集合,这将是一个有意义的url。
这仍然留下了一些灰色地带,因为有些path可能指出父母资源的孩子有多less,这些资源有些是随意的,并取决于他们的使用。 这个绘制的一个难题是任何types的传递表示都应该使用查询参数来完成,因为它不会有底层资源。
为了回应原始问题(Twitter的API)中给出的真实世界的例子,这些参数表示一个传递性查询,它过滤了资源的状态(而不是层次结构)。 在这个特定的例子中,向这些约束表示的集合添加是完全不合理的,并且进一步地,该查询将不能被表示为在对象图的术语中有意义的path。
采用这种types的面向资源的视angular可以很容易地直接映射到您的领域模型的对象图,并将API的逻辑驱动到一切工作都非常干净的程度,并且一旦清晰起见,就会以相当自我logging的方式进行操作。 通过将传统的URL路由映射到通常不适合的数据模型(即RDBMS)的系统,该概念也可以变得更加清晰。 Apache Sling肯定会是一个很好的开始。 Zope等系统中的对象遍历调度的概念也提供了更清晰的模拟。
这是我的意见。
查询参数用作请求的元数据。 它们充当现有资源调用的filter或修饰符。
例:
/calendar/2014-08-08/events
应该给那天的日历事件。
如果你想要一个特定类别的事件
/calendar/2014-08-08/events?category=appointments
或者如果您需要超过30分钟的事件
/calendar/2014-08-08/events?duration=30
石蕊testing将是检查请求是否仍然可以在没有查询参数的情况下被服务。
我通常倾向于#2,作为查询参数(即/ API /资源?参数=值)。
第三个select是实际发布参数=值的正文。
这是因为它对于多参数资源更好,并且对于将来的使用更具可扩展性。
无论你select哪一个,确保你只挑一个,不要混搭。 这导致了一个令人困惑的API。
这个话题的一个“维度”已经被排除了,但是这个问题是非常重要的:有些时候,“最佳实践”必须与我们正在实施的RESTfunction平台或增强RESTfunction的平台一致。
实际例子:
现在许多Web应用程序都实现了MVC(模型,视图,控制器)体系结构。 他们假设提供了一个特定的标准path,当那些Web应用程序带有“启用SEO URL”选项时,甚至更多。
只要提到一个相当有名的Web应用程序:一个OpenCart电子商务商店。 当pipe理员启用“search引擎优化url”时,期望所述url可以采用相当标准的MVC格式,例如:
http://www.domain.tld/special-offers/list-all?limit=25
哪里
-
special-offers
是MVC控制器,它将处理URL(显示特价商品页面) -
list-all
是要调用的控制器的动作或函数名称。 (*) -
限制= 25是一个选项,说明每页显示25个项目。
(*) list-all
是我为清楚起见而使用的一个虚构的函数名称。 实际上,OpenCart和大多数MVC框架都有一个默认的,隐含的(通常在URL中省略) index
函数,当用户想要执行一个默认的动作时被调用。 所以现实世界的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
)。
因此,作为开发人员,您面临着处理现有的基础架构,并调整您的“最佳实践”,除非您是系统pipe理员,确切知道如何调整Apache / NGinx重写configuration(后者可能是讨厌的!上。
因此,遵循引用的Web应用程序的标准,您的REST API往往会更好,这是为了保持一致性,以及缓解/速度(从而节省预算)。
为了回到上面的实际例子,一个一致的REST API将会是这样的URL:
http://www.domain.tld/api/special-offers-list?from=15&limit=25
或(非SEOurl)
http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25
与“path形成”的论点和“查询形成”的论点混合。
我看到很多不能很好地处理参数的REST API。 一个常见的例子是当URI包含个人身份信息时。
http://software.danielwatrous.com/design-principles-for-rest-apis/
我认为一个必然的问题是什么时候一个参数根本不应该是一个参数,而应该被移动到请求的HEADER或者BODY 。
这是一个非常有趣的问题。
你可以使用它们两个,对这个主题没有任何严格的规则,但是使用URIpathvariables有一些优点:
- caching :互联网上的大多数Webcaching服务在包含查询参数时都不cachingGET请求。 他们这样做是因为有很多RPC系统使用GET请求来更改服务器中的数据(失败!!获取必须是安全的方法)
但是,如果您使用pathvariables,所有这些服务可以caching您的GET请求。
- 层次结构 :pathvariables可以表示层次结构:/ City / Street / Place
它为用户提供了关于数据结构的更多信息。
但是,如果您的数据没有任何层次结构关系,则仍然可以使用逗号或分号使用pathvariables:
/市/经度,纬度
通常,在参数sorting时使用逗号,在sorting无关紧要时使用分号。
/ IconGenerator /红色,蓝色,绿色
除了这些原因之外,还有一些情况是使用查询stringvariables很常见:
- 当您需要浏览器自动将HTML表单variables放入URI中时
- 当你正在处理algorithm。 例如,谷歌引擎使用查询string:
http:// http://www.google.com/search?q=rest
总而言之,没有什么强烈的理由使用这个方法,但是只要你可以使用URIvariables。