简体   繁体   English

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

[英]should I put connecting words in my restful api or not?

Let's say I have a controller that takes three parameters: 假设我有一个控制器,它有三个参数:

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

My url for accessing that might be: 我访问的网址可能是:

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

In that case, you have to remember that the parameters map to dogId , commandId & rewardId in that order. 在这种情况下,您必须记住参数按dogId映射到dogIdcommandIdrewardId The other way to go might be something like: 另一种方式可能是:

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

or for even more clarity (but probably more jiggery-pokery with your framework): 或者为了更清晰(但可能更多的jiggery-pokery与您的框架):

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

Which is better? 哪个更好? Which is more common? 哪个更常见? At first blush it seems like clearer is better. 乍一看似乎更清晰更好。 However, you still have to remember what the order of the parameters is, and now you have to remember the key-words, as well. 但是,您仍然需要记住参数的顺序,现在您还必须记住关键字。 ("Was it 'dog/command/reward' or 'command/dog/reward' or 'dog/to/for' or...?") (“它是'狗/命令/奖励'还是'命令/狗/奖励'或'狗/到/为'或......?”

Thoughts? 思考? References? 参考文献? :) :)

You don't appear to be creating a RESTful API here. 您似乎没有在此处创建RESTful API。 REST APIs use URIs to denote resources, not operations ( tell looks like an operation to me). REST API使用URI来表示资源,而不是操作( tell我看起来像是一个操作)。 Operations on resources are defined by an interface that is common to all resources. 资源操作由所有资源共有的接口定义。 I assume you're designing a REST API using HTTP, so your common interface is defined by the HTTP verbs GET, POST, PUT, DELETE, etc. 我假设您正在使用HTTP设计REST API,因此您的公共接口由HTTP动词GET,POST,PUT,DELETE等定义。

So, rather than define our service in terms of the operation tell , lets start by thinking about a resource: dog. 因此,不要根据操作tell来定义我们的服务,让我们从思考资源开始:狗。 As a client, lets assume I'm looking for Rover the dog. 作为一个客户,让我们假设我正在寻找罗孚狗。 My first interaction with your service might be a request like: 我与您的服务的第一次互动可能是以下请求:

GET mysite.com/dogs?q=Rover

Within the response to this request, lets assume that I am given a URL of a resource that represents Rover the dog: mysite.com/dogs/3759 在对此请求的响应中,我们假设我获得了一个代表Rover狗的资源的URL: mysite.com/dogs/3759

Now, lets find out the state of Rover the dog: 现在,让我们找出罗孚狗的状态:

GET mysite.com/dogs/3739

In the response, I see that Rover the dog is alive, awake and standing up (ie the response tells me the state of Rover the dog). 在回应中,我看到罗孚狗还活着,醒着站起来(即响应告诉我罗孚的状态 )。 The response also includes forms which I can use to cause a transition in the state of this resource (ie the response tells me how to make Rover change state). 响应还包括我可用于导致此资源状态转换的表单(即响应告诉我如何使Rover更改状态)。

Now, the next step is to tell Rover to do something. 现在,下一步是告诉罗孚做点什么。 We want Rover's state to transition from standing to sitting (lets assume that we can't simply update Rovers state from standing to sitting, we can only issue a command which Rover can choose to follow - just like a real dog!). 我们希望罗孚的状态从站立转变为坐着(假设我们不能简单地更新流浪者状态从站立到坐着,我们只能发出一个罗孚可以选择遵循的命令 - 就像一只真正的狗!)。 Lets post a sit command to Rover: 让我们向Rover发布一个sit命令:

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

We can think of the command as a resource in it's own right - it has a 'name' (sit) an issuer (me), a dog (Rover) and it may also be followed or unfollowed (depending on the dog's mood). 我们可以将命令视为一种资源 - 它有一个'名称'(坐)发行者(我),一只狗(流浪者),也可以跟随或取消跟随(取决于狗的心情)。 Now in my response to this POST I get the following information 现在,在我对此POST的回复中,我得到以下信息

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

The status tells me that this data has been received by Rover and it has caused the creation of a new resource (our command). 状态告诉我Rover已收到此数据,并且已导致创建新资源(我们的命令)。 If we want to get the state of this command, we can see it by making a request to the URL given in the Location header. 如果我们想获得此命令的状态,我们可以通过对Location头中给出的URL发出请求来查看它。 Let's do that, and find out about our newly created command: 让我们这样做,找出我们新创建的命令:

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

Now the response will tell me the state of this command. 现在响应将告诉我该命令的状态。 Let's assume we're in luck: the command has been followed (the representation returned for this resource includes some information like followed=true ). 让我们假设我们很幸运:已经遵循了命令(为此资源返回的表示包括一些信息,如followed=true )。 The response also includes a link back to the resource that represents Rover (the dog to which the command was issued). 响应还包括一个返回资源的链接,该资源代表Rover(发出命令的狗)。

Finally, when we request the state of the resource that represents Rover: 最后,当我们请求代表Rover的资源的状态时:

GET mysite.com/dogs/3739

We see from the response that a state transition has occurred, and we are now told that Rover is 'sitting'. 我们从回应中看到国家转型已经发生,我们现在被告知罗孚是“坐着”。 The response may also include a reference to the list of commands that Rover has been issue to-date in the form of a link to this URI: 响应还可能包括对Rover迄今为止以此URI链接形式发布的命令列表的引用:

mysite.com/dogs/3739/commands/

This is IMO much closer to a RESTful model. 这是IMO更接近RESTful模型。 The domain you've chosen here may make things harder to explain and understand I think. 你在这里选择的域名可能会让我更难以解释和理解。 A 'command' resource is confusing and sounds very RPC, but the word 'command' is really just used because we're talking about pets. “命令”资源令人困惑,听起来非常冗余,但“命令”这个词实际上只是因为我们谈论的是宠物。 In reality a 'command' is simply a message that you send to a dog. 实际上,“命令”只是您发送给狗的消息。 When we substitute the word 'command' for the word 'message', it's easier to see that a message is a resource that certainly has a state. 当我们将“命令”一词替换为“消息”这个词时,更容易看出消息是一种肯定具有状态的资源。

So in short (tl;dr): 所以简而言之(tl; dr):

  • give URIs to resources, not operations 给资源提供URI,而不是操作
  • create/update resources (cause state transitions) by sending data (not 'invoking operations') 通过发送数据创建/更新资源(导致状态转换)(不是'调用操作')
  • if you can, with every response to your client, help them to make the next state transition using links and forms (these allow the client to update their own state, and to update application state). 如果可以,通过对客户端的每个响应,帮助他们使用链接和表单进行下一次状态转换(这些允许客户端更新自己的状态,并更新应用程序状态)。

For more reading there's a great example of RESTful interaction described here: 有关更多阅读,这里描述了RESTful交互的一个很好的例子:

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

This coffee shop example is refined and expanded upon in Jim Webber and Ian Robinson's book 'REST in Practice'. 这个咖啡店的例子在Jim Webber和Ian Robinson的书“REST in Practice”中得到了完善和扩展。

Of course it may also be worth re-reading Fielding (section 5.2 most relevant I think): 当然,重新阅读菲尔丁也是值得的(我认为第5.2节最相关):

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

Hard to explain in one post (sorry for the length!) but I hope this helps. 很难在一篇文章中解释(对不起长度!)但我希望这会有所帮助。

Personally, i'd prefer to have a url like mysite.com/dog/1/tell , and pass it command=2 and reward=3 via POST. 就个人而言,我更喜欢拥有像mysite.com/dog/1/tell这样的网址,并通过POST传递命令= 2和奖励= 3。 Perhaps the dog ID could be in the data too. 狗ID可能也在数据中。 Several reasons: 几个原因:

  1. Actions that have consequences should not be done via GET, but having the whole request in the URL makes GET very tempting. 具有后果的操作不应该通过GET完成,但是在URL中拥有整个请求会使GET非常诱人。
  2. REST only says that the request should contain everything needed to perform the action, not that the URL should. REST仅表示请求应包含执行操作所需的所有内容,而不是URL应该包含的内容。 Considering #1, i'd even say stuffing everything into a gettable URL is a bad idea. 考虑到#1,我甚至会说将所有内容都填充到可获取的URL中是一个坏主意。
  3. Makes it a lot more versatile; 使它更加通用; an HTML form posting at the URL would be enough to test it. 在URL上发布HTML表单就足以测试它。
  4. As mentioned by someone else, URLs are intended to form a hierarchical namespace. 正如其他人所提到的,URL旨在形成分层命名空间。 You break that when you put your params in the URL, as (1) there's no clear parent/child relationship between, say, 'command' and 'reward', and (2) if none of the params are optional, it makes for a lot of invalid URLs. 当你把params放在URL中时,你会打破这种情况,因为(1)在'command'和'reward'之间没有明确的父/子关系,并且(2)如果没有params是可选的,它会使很多无效的网址。 Naming the params makes it even worse, as now the same "resource" has 6 different and identically-functioning URLs...and that's if your framework actually supports doing that. 命名params使它更糟糕,因为现在相同的“资源”有6个不同且功能相同的URL ......如果你的框架实际上支持这样做的话。

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

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

looks very much like 看起来非常像

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

In the second case, order is definitely not important. 在第二种情况下,订单绝对不重要。 Most probably, it's not important in the first case, either. 最有可能的是,它在第​​一种情况下也不重要。 If I were you, I'd accept any combination, because it's clearly not hierarchical as URLs are expected to be. 如果我是你,我会接受任何组合,因为它显然不是层次结构,因为URL是预期的。 Moreover, you can't expect mysite.com/tell/dog/1 do something useful. 而且,你不能指望mysite.com/tell/dog/1做一些有用的事情。

Since dog id, command id, and reward id only make sense together, I'd state this fact, setting the order, too: 由于狗id,命令id和奖励id只能一起使用,我也说明了这个事实,也是如此:

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

or even 甚至

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

because you can't expect mysite.com/tell/dog-a-command-rewarding-by/1 do something useful, too. 因为你不能指望mysite.com/tell/dog-a-command-rewarding-by/1做一些有用的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM