我应该在我宁静的api中加入连接词吗?

时间:2011-03-19 16:42:44

标签: api rest

假设我有一个控制器,它有三个参数:

class Dog {
    function tell (dogId, commandId, rewardId) {
         // blah
    }
}

我访问的网址可能是:

 mysite.com/dog/tell/1/2/3

在这种情况下,您必须记住参数映射到dogIdcommandId&按此顺序rewardId。另一种方式可能是:

mysite.com/dog/tell/1/command/2/reward/3

或者为了更清晰(但可能更多的jiggery-pokery与您的框架):

mysite.com/tell/dog/1/command/2/reward/3

哪个更好?哪个更常见?乍一看似乎更清晰更好。但是,您仍然需要记住参数的顺序,现在您还必须记住关键字。 (“是'狗/命令/奖励'还是'命令/狗/奖励'或'狗/到/为'或......?”

思考?参考文献? :)

4 个答案:

答案 0 :(得分:4)

您似乎没有在此处创建RESTful API。 REST API使用URI来表示资源,而不是操作(tell看起来像是对我的操作)。资源操作由所有资源共有的接口定义。我假设您正在使用HTTP设计REST API,因此您的公共接口由HTTP动词GET,POST,PUT,DELETE等定义。

因此,我们不是根据操作tell来定义我们的服务,而是从思考资源开始:狗。作为一个客户,让我们假设我正在寻找罗孚狗。我与您的服务的第一次互动可能是以下请求:

GET mysite.com/dogs?q=Rover

在对此请求的回复中,我们假设我获得了一个代表Rover狗的资源的URL:mysite.com/dogs/3759

现在,让我们找出罗孚狗的状态:

GET mysite.com/dogs/3739

在回答中,我看到罗孚狗还活着,醒着站起来(即响应告诉我罗孚狗的)。响应还包括我可用于导致此资源状态转换的表单(即响应告诉我如何使Rover更改状态)。

现在,下一步是告诉罗孚做点什么。我们希望罗孚的状态从站立转变为坐着(假设我们不能简单地更新流浪者状态从站立到坐着,我们只能发出一个罗孚可以选择遵循的命令 - 就像一只真正的狗!)。让我们向Rover发布sit命令:

POST mysite.com/dogs/3739
<command name="sit"/>

我们可以将命令视为资源本身 - 它有一个'名字'(坐着)发行人(我),一只狗(流浪者),它也可能被跟随或取消跟踪(取决于狗的心情)。现在,在我对此POST的回复中,我得到以下信息

Status  : 201 (Created)
Location: mysite.com/dogs/3739/commands/1299

状态告诉我Rover已收到此数据,并导致创建新资源(我们的命令)。如果我们想获得此命令的状态,我们可以通过对Location头中给出的URL发出请求来查看它。让我们这样做,并找出我们新创建的命令:

GET mysite.com/dogs/3739/commands/1299

现在响应会告诉我这个命令的状态。让我们假设我们很幸运:已经遵循了命令(为此资源返回的表示包括一些信息,如followed=true)。响应还包括一个返回资源的链接,该资源代表Rover(发出命令的狗)。

最后,当我们请求代表Rover的资源状态时:

GET mysite.com/dogs/3739

我们从回应中看到状态转变已经发生,我们现在被告知罗孚是“坐着”。响应还可能包括对Rover迄今为止以此URI链接形式发布的命令列表的引用:

mysite.com/dogs/3739/commands/

这是IMO更接近RESTful模型。你在这里选择的域名可能会让我更难以解释和理解。 “命令”资源令人困惑,听起来非常冗余,但“命令”这个词实际上只是因为我们谈论的是宠物。实际上,“命令”只是您发送给狗的消息。当我们用“命令”这个词替换“消息”这个词时,就会更容易看到一条消息是一个肯定有状态的资源。

简而言之(tl; dr):

  • 为资源提供URI,而不是操作
  • 通过发送数据(不是“调用操作”)来创建/更新资源(导致状态转换)
  • 如果可以的话,每次回复客户端,都可以帮助他们使用链接和表单进行下一次状态转换(这些允许客户端更新自己的状态,并更新应用程序状态)。

如需更多阅读,这里有一个很好的RESTful交互示例:

http://www.infoq.com/articles/webber-rest-workflow

这个咖啡店的例子在Jim Webber和Ian Robinson的书“REST in Practice”中得到了完善和扩展。

当然,重新阅读菲尔丁也是值得的(我认为第5.2节最相关):

http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

很难在一篇文章中解释(抱歉篇幅!)但我希望这会有所帮助。

答案 1 :(得分:1)

就个人而言,我更喜欢拥有像mysite.com/dog/1/tell这样的网址,并通过POST传递命令= 2和奖励= 3。狗ID可能也在数据中。 有几个原因:

  1. 不应该通过GET完成具有后果的操作,但是在URL中包含整个请求会使GET非常诱人。
  2. REST仅表示请求应包含执行操作所需的所有内容,而不是URL应该包含的内容。考虑到#1,我甚至说把所有内容都塞进一个可获取的URL是一个坏主意。
  3. 使它变得更加通用;在URL上发布HTML表单就足以对其进行测试。
  4. 正如其他人所提到的,URL旨在形成分层命名空间。当你把params放在URL中时,你会打破这种情况,因为(1)在'command'和'reward'之间没有明确的父/子关系,并且(2)如果没有params是可选的,它会使很多无效的网址。命名params使它更糟糕,因为现在相同的“资源”有6个不同且功能相同的URL ......如果你的框架实际上支持这样做的话。

答案 2 :(得分:0)

对于一个网站,我会说连接词是有用的,对于api,我说不是真的,好的文档就是api所需要的。

答案 3 :(得分:0)

mysite.com/tell/dog/1/command/2/reward/3

非常像

mysite.com/tell?dog=1&command=2&reward=3

在第二种情况下,订单绝对不重要。最有可能的是,它在第​​一种情况下也不重要。如果我是你,我会接受任何组合,因为它显然不是层次结构,因为URL是预期的。此外,您不能指望mysite.com/tell/dog/1做一些有用的事情。

由于狗ID,命令ID和奖励ID只能一起使用,我也会说明这个事实,设定顺序:

mysite.com/tell/dog-a-command-rewarding-by/1/2/3

甚至

mysite.com/tell/dog-a-command-rewarding-by/1-2-3

因为你不能指望mysite.com/tell/dog-a-command-rewarding-by/1做一些有用的事情。