3

We're trying to re-engineer our SOAP API to a RESTful one (using ASP.NET Web Api).

I know the question of how to replace RPC-style calls with REST comes up a lot but I still haven't found anything that quite gets me where I want. It may be a failure of imagination or a fundamental misunderstanding of REST principles (I'll let you be the judge of that!)

I've created an example below which roughly maps to the kind of thing I'm trying to achieve.

Suppose we have a resource which I'll call Booking

GET .../Bookings/Booking/1

And we have a requirement to cancel this booking which previously would have been modelled with something like.

...CancelBooking(1, Reasons.NoLongerRequired)

So it's the booking ID and a reason code.

Or we may need the ability to cancel multiple bookings in a single request.

...CancelBooking("1,2,3", Reasons.NoLongerRequired)

(A little crude but I'm trying to keep the example simple!)

How would we best model this in a RESTful architecture?

One suggestion is that we have a resource called something like a CancellationRequest and we POST one of these to the server?

POST .../Bookings/CancellationRequest    
{
  "BookingIDs" : "1,2,3",   
  "CancellationReason" : "NotRequired"
}

Perhaps this would do the processing and then return a redirect to the cancelled Booking(s)?

But I don't know if this is the best approach in terms of REST.

Can anyone advise?

David Scott
  • 153
  • 1
  • 11

1 Answers1

2

(One note: it's redundant to say /Bookings/Booking/:id. I'm also of the opinion that resources should begin with lowercase letters. In that case, you'd address the resource as /bookings/:id).

There's a decent amount of opinion amongst designers what the correct way should be. I'm personally not a fan of adhering so closely to RESTful conventions that it makes the API chatty or difficult to or understand.

However, your case seems pretty straightforward:

Multiple resources:

DELETE /bookings?reasonCode=Reasons.NoLongerRequired&id=1&id=2&id=3

Single resource:

DELETE /bookings?reasonCode=Reasons.NoLongerRequired&id=1

which degenerates to

DELETE /bookings/:id?reasonCode=Reasons.NoLongerRequired

Also see Patterns for handling batch operations in REST web services?

Community
  • 1
  • 1
Palpatim
  • 9,074
  • 35
  • 43
  • Many thanks. (And yes I'm not entirely sure why I describe included the additional /Bookings - lack of sleep probably!! I'll also take on board what you said about lower case). Suppose we want to retain the Booking as a record. Suppose the verb is something like "suspend" ? Something that indicates we want to do something to this booking but we don't want to delete it. Essentially a status change. I think what I'm saying is that I've used a bad example with "cancel". (lack of sleep again?). I'll take a look at the link you've included. Thanks again. – David Scott Feb 19 '14 at 09:24
  • That's simply an update, so the correct verb would be a `PUT` with the appropriate payload: `PUT /bookings/:id` with a payload of something like `{"status":"cancelled","reason":"Reasons.NoLongerRequired"}`. I've worked on many systems that modeled their "cancelations" this way, and nary a `DELETE` to be found in the API. – Palpatim Feb 19 '14 at 15:41
  • @Palpatim a PUT like that would be inappropriate since a PUT should update the entire resource to match your body. That would mean that the entire booking resource would have to be in your request for it to be correct; only sending pieces of it (e.g. Status) would result in the nulling of all the other fields. Partial updates like that are a PATCH. However, I dont think it should be a DELETE either since the resource isn't actually being deleted. To use a DELETE, I would say it would only be appropriate if that resource no longer has a fetchable representation following the DELETE. – Sinaesthetic Dec 11 '15 at 13:00