Keep in mind I have a rudimentary understanding of REST. Let's say I have this URL:
http://api.animals.com/v1/dogs/1/
And now, I want to make the server make the dog bark. Only the server knows how to do this. Let's say I want to have it run on a CRON job that makes the dog bark every 10 minutes for the rest of eternity. What does that call look like? I kind of want to do this:
URL request:
ACTION http://api.animals.com/v1/dogs/1/
In the request body:
{"action":"bark"}
Before you get mad at me for making up my own HTTP method, help me out and give me a better idea on how I should invoke a server-side method in a RESTful way. :)
EDIT FOR CLARIFICATION
Some more clarification around what the "bark" method does. Here are some options that may result in differently structured API calls:
- bark just sends an email to dog.email and records nothing.
- bark sends an email to dog.email and the increments dog.barkCount by 1.
- bark creates a new "bark" record with bark.timestamp recording when the bark occured. It also increments dog.barkCount by 1.
- bark runs a system command to pull the latest version of the dog code down from Github. It then sends a text message to dog.owner telling them that the new dog code is in production.
REST is a resource oriented standard, it is not action driven as a RPC would be.
If you want your server to bark, you should look into different ideas like JSON-RPC, or into websockets communication.
Every try to keep it RESTful will fail in my opinion: you can issue a
POST
with theaction
parameter, you are not creating any new resources but as you may have side effects, you are safer.If we assume Barking is an inner / dependent / sub resource which the consumer can act on, then we could say:
dog number 1 barks
returns the last bark timestamp
doesn't apply! so ignore it.
I answered earlier, but this answer contradicts my old answer and follows a much different strategy for coming to a solution. It shows how the HTTP request is built from the concepts that define REST and HTTP. It also uses
PATCH
instead ofPOST
orPUT
.It goes through the REST constraints, then the components of HTTP, then a possible solution.
REST
REST is a set of constraints intended to be applied to a distributed hypermedia system in order to make it scalable. Even to make sense of it in the context of remotely controlling an action, you have to think of remotely controlling an action as a part of a distributed hypermedia system -- a part of a system for discovering, viewing, and modifying interconnected information. If that's more trouble than it's worth, then it's probably no good to try to make it RESTful. If you just want a "control panel" type GUI on the client that can trigger actions on the server via port 80, then you probably want a simple RPC interface like JSON-RPC via HTTP requests/responses or a WebSocket.
But REST is a fascinating way of thinking and the example in the question happens to be easy to model with a RESTful interface, so let's take on the challenge for fun and for education.
REST is defined by four interface constraints:
You ask how you can define an interface, meeting these constraints, via which one computer tells another computer to make a dog bark. Specifically, you want your interface to be HTTP, and you don't want to discard the features that make HTTP RESTful when used as intended.
Let's begin with the first constraint: resource identification.
So a dog is a resource. It needs to be identified.
You model a dog by taking a set of identifiers and representations and saying they are all associated with each other at a given time. For now, let's use the identifier "dog #1". That brings us to the second and third constraints: resource representation and self-description.
Following is a sequence of bytes capturing the intended state of the dog, i.e. the representation we wish to be associated with the identifier "dog #1" (note that it only represents part of the state as it does not regard the dog's name, health, or even past barks):
It is supposed to be attached to metadata that describes it. This metadata might be useful:
Finally, let's look at the fourth constraint: HATEOAS.
In a RESTful interface, the client receives a resource representation in order to figure out how it should receive or send a representation. There must be a representation somewhere in the application from which the client can figure out how to receive or send all representations it should be able to receive or send, even if it follows a chain of representations to arrive at that information. This seems simple enough:
The client asks for a representation of a resource identified as the homepage; in response, it gets a representation that contains an identifier of every dog the client might want. The client extracts an identifier from it and asks the service how it can interact with the identified dog, and the service says the client can send an English statement describing part of the intended state of the dog. Then the client sends such a statement and receives a success message or an error message.
HTTP
HTTP implements REST constraints as follows:
resource identification: URI
resource representation: entity-body
self-description: method or status code, headers, and possibly parts of the entity-body (e.g. the URI of an XML schema)
HATEOAS: hyperlinks
You've decided on
http://api.animals.com/v1/dogs/1
as the URI. Let's assume the client got this from some page on the site.Let's use this entity-body (the value of
next
is a timestamp; a value of0
means 'when this request is received'):Now we need a method. PATCH fits the "part of the intended state" description we decided on:
And some headers:
To indicate the language of the entity-body:
Content-Type: application/json
To make sure it only happens once:
If-Unmodified-Since: <date/time this was first sent>
And we have a request:
On success, the client should receive a
204
status code in response, or a205
if the representation of/v1/dogs/1/
has changed to reflect the new barking schedule.On failure, it should receive a
403
and a helpful message why.It is not essential to REST for the service to reflect the bark schedule in a representation in response to
GET /v1/dogs/1/
, but it would make the most sense if a JSON representation included this:Treat the cron job as an implementation detail that the server hides from the interface. That's the beauty of a generic interface. The client doesn't have to know what the server does behind the scenes; all it cares about is that the service understands and responds to requested state changes.
Why aim for a RESTful design?
The RESTful principles bring the features that make web sites easy (for a random human user to "surf" them) to the web services API design, so they are easy for a programmer to use. REST isn't good because it's REST, it's good because it's good. And it is good mostly because it is simple.
The simplicity of plain HTTP (without SOAP envelopes and single-URI overloaded
POST
services), what some may call "lack of features", is actually its greatest strength. Right off the bat, HTTP asks you to have addressability and statelessness: the two basic design decisions that keep HTTP scalable up to today's mega-sites (and mega-services).But REST is not the silver bulltet: Sometimes an RPC-style ("Remote Procedure Call" - such as SOAP) may be appropriate, and sometimes other needs take precedence over the virtues of the Web. This is fine. What we don't really like is needless complexity. Too often a programmer or a company brings in RPC-style Services for a job that plain old HTTP could handle just fine. The effect is that HTTP is reduced to a transport protocol for an enormous XML payload that explains what's "really" going on (not the URI or the HTTP method give a clue about it). The resulting service is far too complex, impossible to debug, and won't work unless your clients have the exact setup as the developer intended.
Same way a Java/C# code can be not object-oriented, just using HTTP does not make a design RESTful. One may be caught up in the rush of thinking about his services in terms of actions and remote methods that should be called. No wonder this will mostly end up in a RPC-Style service (or a REST-RPC-hybrid). The first step is to think different. A RESTful design can be achieved in many ways, one way (the simplest, some might say) is to think of your application in terms of resources, not actions:
I'll go for examples below. (Other key aspect of REST is the use of HATEOAS - I don't brush it here, but I talk about it quickly at another post.)
About the first design
Let's take a look a the proposed design:
First off, we should not consider creating a new HTTP verb (
ACTION
). Generally speaking, this is undesirable for several reasons:ACTION
verb exists?Now let's consider using
POST
(I'll discuss why below, just take my word for it now):This could be OK... but only if:
{"action":"bark"}
was a document; and/v1/dogs/1/
was a "document processor" (factory-like) URI. A "document processor" is a URI that you'd just "throw things at" and "forget" about them - the processor may redirect you to a newly created resource after the "throwing". E.g. the URI for posting messages at a message broker service, which, after the posting would redirect you to a URI that shows the status of the message's processing.I don't know much about your system, but I'd already bet both aren't true:
{"action":"bark"}
is not a document, it actually is the method you are trying to ninja-sneak into the service; and/v1/dogs/1/
URI represents a "dog" resource (probably the dog withid==1
) and not a document processor.So all we know now is that the design above is not so RESTful, but what is that exactly? What is so bad about it? Basically, it is bad because that is complex URI with complex meanings. You can't infer anything from it. How would a programmer know a dog have a
bark
action that can be secretly infused with aPOST
into it?Designing your question's API calls
So let's cut to the chase and try to design those barks RESTfully by thinking in terms of resources. Allow me to quote the Restful Web Services book:
Following the description above we can see that
bark
can be modeled as a subresource of adog
(since abark
is contained within a dog, that is, a bark is "barked" by a dog).From that reasoning we already got:
POST
/barks
, subresource of dog:/v1/dogs/1/barks
, representing abark
"factory". That URI is unique for each dog (since it is under/v1/dogs/{id}
).Now each case of your list has a specific behavior.
1. bark just sends an e-mail to
dog.email
and records nothing.Firstly, is barking (sending an e-mail) a synchronous or an asynchronous task? Secondly does the
bark
request require any document (the e-mail, maybe) or is it empty?1.1 bark sends an e-mail to
dog.email
and records nothing (as a synchronous task)This case is simple. A call to the
barks
factory resource yields a bark (an e-mail sent) right away and the response (if OK or not) is given right away:As it records (changes) nothing,
200 OK
is enough. It shows that everything went as expected.1.2 bark sends an e-mail to
dog.email
and records nothing (as an asynchronous task)In this case, the client must have a way to track the
bark
task. Thebark
task then should be a resource with it's own URI.:This way, each
bark
is traceable. The client can then issue aGET
to thebark
URI to know it's current state. Maybe even use aDELETE
to cancel it.2. bark sends an e-mail to
dog.email
and then incrementsdog.barkCount
by 1This one can be trickier, if you want to let the client know the
dog
resource gets changed:In this case, the
location
header's intent is to let the client know he should take a look atdog
. From the HTTP RFC about303
:If the task is asynchronous, a
bark
subresource is needed just like the1.2
situation and the303
should be returned at aGET .../barks/Y
when the task is complete.3. bark creates a new "
bark
" record withbark.timestamp
recording when the bark occured. It also incrementsdog.barkCount
by 1.In here, the
bark
is a created due to the request, so the status201 Created
is applied.If the creation is asynchronous, a
202 Accepted
is required (as the HTTP RFC says) instead.The timestamp saved is a part of
bark
resource and can be retrieved with aGET
to it. The updated dog can be "documented" in thatGET dogs/X/barks/Y
as well.4. bark runs a system command to pull the latest version of the dog code down from Github. It then sends a text message to
dog.owner
telling them that the new dog code is in production.The wording of this one is complicated, but it pretty much is a simple asynchronous task:
The client then would issue
GET
s to/v1/dogs/1/barks/a65h44
to know the current state (if the code was pulled, it the e-mail was sent to the owner and such). Whenever the dog changes, a303
is appliable.Wrapping up
Quoting Roy Fielding:
In the above examples,
POST
is uniformly designed. It will make the dog "bark
". That is not safe (meaning bark has effects on the resources), nor idempotent (each request yields a newbark
), which fits thePOST
verb well.A programmer would know: a
POST
tobarks
yields abark
. The response status codes (also with entity-body and headers when necessary) do the job of explaining what changed and how the client can and should proceed.Note: The primary sources used were: "Restful Web Services" book, the HTTP RFC and Roy Fielding's blog.
Edit:
The question and thus the answer have changed quite a bit since they were first created. The original question asked about the design of a URI like:
Below is the explanation of why it is not a good choice:
How clients tell the server WHAT TO DO with the data is the method information.
WHICH PART of the data [the client wants the server] to operate on is the scoping information.
As an example, take Google's URI
http://www.google.com/search?q=DOG
. There, the method information isGET
and the scoping information is/search?q=DOG
.Long story short:
And the rule of thumb:
You can put the "bark" "action" in the URL (or in the entity-body) and use
POST
. No problem there, it works, and may be the simplest way to do it, but this isn't RESTful.To keep your service really RESTful, you may have to take a step back and think about what you really want to do here (what effects will it have on the resources).
I can't talk about your specific business needs, but let me give you an example: Consider a RESTful ordering service where orders are at URIs like
example.com/order/123
.Now say we want to cancel an order, how are we gonna do it? One may be tempted to think that is a "cancellation" "action" and design it as
POST example.com/order/123?do=cancel
.That is not RESTful, as we talked above. Instead, we might
PUT
a new representation of theorder
with acanceled
element sent totrue
:And that's it. If the order can't be canceled, a specific status code can be returned. (A subresource design, like
POST /order/123/canceled
with the entity-bodytrue
may, for simplicity, also be available.)In your specific scenario, you may try something similar. That way, while a dog is barking, for example, a
GET
at/v1/dogs/1/
could include that information (e.g.<barking>true</barking>
). Or... if that's too complicated, loosen up your RESTful requirement and stick withPOST
.Update:
I don't want to make the answer too big, but it takes a while to get the hang of exposing an algorithm (an action) as a set of resources. Instead of thinking in terms of actions ("do a search for places on the map"), one needs to think in terms of the results of that action ("the list of places on the map matching a search criteria").
You may find yourself coming back to this step if you find that your design doesn't fit HTTP's uniform interface.
Query variables are scoping information, but do not denote new resources (
/post?lang=en
is clearly the same resource as/post?lang=jp
, just a different representation). Rather, they are used to convey client state (like?page=10
, so that state is not kept in the server;?lang=en
is also an example here) or input parameters to algorithmic resources (/search?q=dogs
,/dogs?code=1
). Again, not distinct resources.HTTP verbs' (methods) properties:
Another clear point that shows
?action=something
in the URI is not RESTful, are the properties of HTTP verbs:GET
andHEAD
are safe (and idempotent);PUT
andDELETE
are idempotent only;POST
is neither.Safety: A
GET
orHEAD
request is a request to read some data, not a request to change any server state. The client can make aGET
orHEAD
request 10 times and it's the same as making it once, or never making it at all.Idempotence: An idempotent operation in one that has the same effect whether you apply it once or more than once (in math, multiplying by zero is idempotent). If you
DELETE
a resource once, deleting again will have the same effect (the resource isGONE
already).POST
is neither safe nor idempotent. Making two identicalPOST
requests to a 'factory' resource will probably result in two subordinate resources containing the same information. With overloaded (method in URI or entity-body)POST
, all bets are off.Both these properties were important to the success of the HTTP protocol (over unreliable networks!): how many times have you updated (
GET
) the page without waiting until it is fully loaded?Creating an action and placing it in the URL clearly breaks the HTTP methods' contract. Once again, the technology allows you, you can do it, but that is not RESTful design.
POST
is the HTTP method designed forServer-side methods handling non-CRUD-mapped actions is what Roy Fielding intended with REST, so you're good there, and that's why
POST
was made to be non-idempotent.POST
will handle most posting of data to server-side methods to process the information.That said, in your dog-barking scenario, if you want a server-side bark to be performed every 10 minutes, but for some reason need the trigger to originate from a client,
PUT
would serve the purpose better, because of its idempotence. Well, strictly by this scenario there's no apparent risk of multiple POST requests causing your dog to meow instead, but anyway that's the purpose of the two similar methods. My answer to a similar SO question may be useful for you.See my new answer -- it contradicts this one and explains REST and HTTP more clearly and accurately.
Here's a recommendation that happens to be RESTful but is certainly not the only option. To start barking when the service receives the request:
token
is an arbitrary number that prevents redundant barks no matter how many times this request is sent.next
indicates the time of the next bark; a value of0
means 'ASAP'.Whenever you
GET /v1/dogs/1/bark-schedule
, you should get something like this, where t is the time of the last bark and u is t + 10 minutes:{"last": t, "next": u}
I highly recommend that you use the same URL to request a bark that you use to find out about the dog's current barking state. It's not essential to REST, but it emphasizes the act of modifying the schedule.
The appropriate status code is probably 205. I'm imagining a client that looks at the current schedule,
POST
s to the same URL to change it, and is instructed by the service to give the schedule a second look to prove that it has been changed.Explanation
REST
Forget about HTTP for a moment. It's essential to understand that a resource is a function that takes time as input and returns a set containing identifiers and representations. Let's simplify that to: a resource is a set R of identifiers and representations; R can change -- members can be added, removed, or modified. (Though it's bad, unstable design to remove or modify identifiers.) We say an identifier that is an element of R identifies R, and that a representation that is an element of R represents R.
Let's say R is a dog. You happen to identify R as
/v1/dogs/1
. (Meaning/v1/dogs/1
is a member of R.) That's just one of many ways you could identify R. You could also identify R as/v1/dogs/1/x-rays
and as/v1/rufus
.How do you represent R? Maybe with a photograph. Maybe with a set of X-rays. Or maybe with an indication of the date and time when R last barked. But remember that these are all representations of the same resource.
/v1/dogs/1/x-rays
is an identifier of the same resource that is represented by an answer to the question "when did R last bark?"HTTP
Multiple representations of a resource aren't very useful if you can't refer to the one you want. That's why HTTP is useful: it lets you connect identifiers to representations. That is, it is a way for the service to receive a URL and decide which representation to serve to the client.
At least, that's what
GET
does.PUT
is basically the inverse ofGET
: youPUT
a representation r at the URL if you wish for futureGET
requests to that URL to return r, with some possible translations like JSON to HTML.POST
is a looser way of modifying a representation. Think of there being display logic and modification logic that are counterparts to each other -- both corresponding to the same URL. A POST request is a request for the modification logic to process the information and modify any representations (not just the representation located by the same URL) as the service sees fit. Pay attention to the third paragraph after 9.6 PUT: you're not replacing the thing at the URL with new content; you're asking the thing at the URL to process some information and intelligently respond in the form of informative representations.In our case, we ask the modification logic at
/v1/dogs/1/bark-schedule
(which is the counterpart to the display logic that tells us when it last barked and when it will next bark) to process our information and modify some representations accordingly. In response to futureGET
s, the display logic corresponding to the same URL will tell us that the dog is now barking as we wish.Think of the cron job as an implementation detail. HTTP deals in viewing and modifying representations. From now on, the service will tell the client when the dog last barked and when it will bark next. From the service's perspective, that is honest because those times correspond with past and planned cron jobs.