简体   繁体   中英

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. 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):

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. REST APIs use URIs to denote resources, not operations ( tell looks like an operation to me). 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.

So, rather than define our service in terms of the operation tell , lets start by thinking about a resource: dog. 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

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).

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:

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

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). 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. 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 ). The response also includes a link back to the resource that represents Rover (the dog to which the command was issued).

Finally, when we request the state of the resource that represents 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:

mysite.com/dogs/3739/commands/

This is IMO much closer to a RESTful model. 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):

  • give URIs to resources, not operations
  • 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:

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'.

Of course it may also be worth re-reading Fielding (section 5.2 most relevant I think):

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. Perhaps the dog ID could be in the data too. 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.
  2. REST only says that the request should contain everything needed to perform the action, not that the URL should. Considering #1, i'd even say stuffing everything into a gettable URL is a bad idea.
  3. Makes it a lot more versatile; an HTML form posting at the URL would be enough to test it.
  4. As mentioned by someone else, URLs are intended to form a hierarchical namespace. 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. 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.

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

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

looks very much like

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. Moreover, you can't expect mysite.com/tell/dog/1 do something useful.

Since dog id, command id, and reward id only make sense together, I'd state this fact, setting the order, too:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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