Reputation: 117
I am in the process of designing a public API for our REST interface. One of the thing's that came up was the use of the http verbs, specifically the DELETE verb.
We want to expose methods to start/stop or execute/abort a particular job. The two flavors of api design for these two are:
POST
http://localhost/api/campaignrun/1
Execute campaign run with an id of 1
DELETE
http://localhost/api/campaignrun/1
Abort the campaign run with an id of 1
Alternatively...
POST
http://localhost/api/campaignrun/1
{ action=execute}
Execute campaign run with an id of 1
POST
http://localhost/api/campaignrun/1
{ action=abort }
Abort campaign run with an id of 1
If have my favorite, which one is more RESTful?
Upvotes: 2
Views: 3283
Reputation: 1408
As many have stated here, DELETE on a resource means that the relevant campaignrun is not accessible anymore (404 Not Found should return afterwards). My guess this is not the intention of aborting the campaignrun.
The following will be more REST compliant to any alternatives mentioned in the question:
http://localhost/api/campaignruns
Note the plural noun (more RESTful, collection->instance->collection->instance...).
This request creates a campaignrun. Let's say, that the campaignrun created ID is 1.
http://localhost/api/campaignruns/1/operations
{
"operation": "execute"
}
http://localhost/api/campaignruns/1/operations
{
"operation": "abort"
}
Let's say, that the abort operation ID is 2.
Here it how it shows (assuming async operation) right after POST:
http://localhost/api/campaignruns/1/operations/2
Response:
{
"id": 2,
"operation": "abort",
"status": "processing"
}
Here how it should look when it is completed:
http://localhost/api/campaignruns/1/operations/2
Response:
{
"id": 2,
"operation": "abort",
"status": "completed"
}
Upvotes: 0
Reputation: 4489
Choosing between your two designs, I would vote for your 2nd one, that uses POST
, but with a small modification: Use PUT
instead:
PUT http://localhost/api/campaignrun/1
{ action: abord }
This API speaks clearly about its intentions: You have campaignruns
(better keep this plural), you want the campainrun that has {id} = 1
, and there is an attribute of that resource called action, which I want to update.
This way, you keep your API consistent with the idempotence of http verbs: PUT
should be idempotent, POST
shouldn't. For your case this means that, no matter how many times a user hits the above request, the result is the same: The campaignrun with id=1 will get aborded.
Note: I see you have accepted an answer that proposes verbs at the URIs, and then uses POST
to them. This post is not a place to argue for or against REST, but since your question is about which design is more RESTful, you should think twice. You may want to check this very nice 38 page free ebook that speaks about best practices for designing APIs. Among others, it suggests to keep verbs out of your base URLs, unless very few cases. Check it out, it would prove helpful!
Upvotes: 2
Reputation: 33789
Is it possible to restart a stopped job? If so, I suggest that you use POST
since you are not really deleting any resource. However, you can change the urls to better indicate what you are trying to achieve:
POST
http://localhost/api/campaignrun/1/start
and
POST
http://localhost/api/campaignrun/1/stop
Thus, there is no need for providing a request body to indicate the type of of action.
Side note: For me DELETE
indicates that the campaign will be removed forever, and thus cannot be restarted. Consequently, a 404 will be returned if the client attempts to access the resource.
Upvotes: 0
Reputation: 137767
If you can use DELETE, that would be great. However, you should only do so if stopping the campaign run means that the client should never access that resource (that particular URL) again. If the client is reasonably expected to interact with the resource afterwards, use POST (or PUT to a sub-resource, of course).
Upvotes: 0
Reputation: 19232
The first is more "Restful". The only issue you will have is if you need to delete instead of abort a campaign run in the future. You can always just pass an action to DELETE if you require campaign run delete record functionality in the future.
Upvotes: 0