It is understandable to be a little confused about how to properly use REST based on all the ways I have seen large companies design their REST APIs.
You are correct in that REST is a Resource Collection system. It stands for Representational State Transfer. Not a great definition if you ask me. But the main concepts are the 4 HTTP VERBs and being stateless.
The important piece to note is that you only have 4 VERBS with REST. These are GET, POST, PUT and DELETE. Your resend
example would be adding a new Verb to REST. This should be a red flag.
Question 1
It is important to realize that the caller of your REST API should not have to know that performing a PUT
on your collection would result in an e-mail being generated. That smells of a leak to me. What they could know is that performing a PUT
could result in extra tasks which they could query later. They would know this by performing a GET
on the recently created resource. That GET
would return the resource and all of the Task
resource id's associated with it. You can then later query those tasks to determine their status and even submit a new Task
.
You have a few options.
REST - Task resource based approach
Create a tasks
resource in which you can submit specific tasks into your system to perform actions. You can then GET
the task based on the ID
it returned to determine it's status.
Or you can mix in a SOAP over HTTP
Web Service in order to add some RPC to your architecture.
querying for all tasks for a specific resource
GET http://server/api/myCollection/123/tasks
{ "tasks" :
[ { "22333" : "http://server/api/tasks/223333" } ]
}
task resource example
PUT http://server/api/tasks
{
"type" : "send-email" ,
"parameters" :
{
"collection-type" : "foo" ,
"collection-id" : "123"
}
}
==> returns id of task
223334
GET http://server/api/tasks/223334
{
"status" : "complete" ,
"date" : "whenever"
}
REST- Using POST to trigger actions
You can always POST
additional data to a resource. In my opinion this would violate the spirit of REST but it would still be compliant.
You can do a POST similar to this:
POST http://server/api/collection/123
{ "action" : "send-email" }
You will be updating the resource 123 from collection with additional data. That additional data is essentially a action telling the backend to send an email for that resource.
The issue I have with this is that a GET
on the resource will return this updated data. However, this would solve your requirements and still be RESTful.
SOAP - Web Service that accepts resources obtained from REST
Create a new WebService in which you can send e-mails based on the previous resource ID from the REST API. I won't go into detail about SOAP here as the original question is about REST and these two concepts/technologies should not be compared as it's Apples and Oranges.
Question 2
You also have a few options here:
It appears many larger companies that publish REST API's expose a search
collection that is really just a way to pass in query parameters to return resources.
GET http://server/api/search?q="type = myCollection & someField >= someval"
Which would return a collection of fully qualified REST resources such as:
{
"results" :
{ [
"location" : "http://server/api/myCollection/1",
"location" : "http://server/api/myCollection/9",
"location" : "http://server/api/myCollection/56"
]
}
}
Or you can allow something like MVEL as a query parameter.
Question 3
I prefer the sub-levels than having to go back up and query the other resource with a query parameter. I do not believe there is any rule one way or another. You can implement both ways and allow the caller to decide which is more appropriate based on how they first entered into the system.
Notes
I disagree about the readability comments from others. Despite what some might think REST is still not for human consumption. It is for machine consumption. If I want to see my Tweets I use Twitters regular website. I do not perform a REST GET with their API. If I want to programmatically do something with my tweets then I use their REST API. Yes APIs should be understandable, but your gte
isn't that bad, it's just not intuitive.
The other main thing with REST is that you should be able to start at any give point in your API and navigate to all other associated resources WITHOUT know the exact URL of the other resources ahead of time. The results of the GET
VERB in REST should return the full REST URL of the resources it references. So instead of a query returning the ID of a Person
object, it would return the Fully Qualified URL such as http://server/api/people/13
. Then you can always programmatically navigate the results even if the URL changed.
Response to comment
In the real world there are in fact things that need to happen that don't Create, Read, Update or Delete (CRUD) a resource.
Additional actions can be taken on resources. Typical relational databases support the concept of Stored Procedures. These are additional commands that can be executed on a set of data. REST does not inherently have that concept. And there is no reason it should. These types of actions are perfect for RPC or SOAP Web Services.
This is the general problem I see with REST APIs. Developers don't like the conceptual limitations that surround REST so they adapt it to do whatever they would like. That breaks it from being a RESTful service though. Essentially those URL's become GET
calls on pseudo-REST-like servlets.
You have a few options:
- Create a task resource
- Support
POST
ing additional data to the resource to perform an action.
- Add the additional commands through a SOAP Web Service.
If you used a query parameter which HTTP VERB would you use to resend the email?
GET
- Does this resend the email AND return the resource's data? What if a system cached that URL and treated it like the unique URL for that resource. Every time they hit the URL it would resend an email.
POST
- You didn't actually send any new data to the resource, just an additional query parameter.
Based on all the given requirements, doing a POST
on the resource with an action field
as POST data will solve the problem.