I am trying to design a RESTful web API for our service using ASP.NET Web API. I'm running into trouble with figuring out how to route non-CRUD actions to the proper controller action. Let's assume my resource is a door. I can do all of the familiar CRUD things with my door. Let's say that model for my door is:
public class Door
{
public long Id { get; set; }
public string InsideRoomName { get; set; }
public string OutsideRoomName { get; set; }
}
I can do all of my standard CRUD operations via my web api:
POST: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors/1234
GET: http://api.contoso.com/v1/doors?InsideRoomName=Cafeteria
PUT: http://api.contoso.com/v1/doors/1234
DELETE: http://api.contoso.com/v1/doors/1234
and so on. Where I run into trouble is when I need to model the non-CRUD actions against my door. I want to model a Lock and Unlock verb against my resource. Reading through the ASP.NET articles the guidance seems to be to switch to an RPC style call when using custom actions. This gives me a path:
PUT: http://api.contoso.com/v1/doors/1234/lock
PUT: http://api.contoso.com/v1/doors/1234/unlock
This seems to conflict with the spirit of REST which aims for the path to indicate a resource. I suppose I could model the verb as a resource:
POST: http://api.contoso.com/v1/doors/1234/lockrequests
POST: http://api.contoso.com/v1/doors/1234/unlockrequests
In this case I could still use the recommend {controller}/{id}/{action} but it seems like I'm still creating a mixed RPC / REST API. Is it possible, or even recommended as far as REST interfaces go, to put the custom action in the list of parameters?
PUT: http://api.contoso.com/v1/doors/1234?lock
PUT: http://api.contoso.com/v1/doors/1234?unlock
I could foresee a need to have this call supported with query parameters as well, such as:
PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria
How would I create the route to map this request to my DoorsController?
public class DoorsController : ApiController
{
public IEnumerable<Doord> Get();
public Door Get(long id);
public void Put(long id, Door door);
public void Post(Door door);
public void Delete(long id);
public void Lock(long id);
public void Unlock(long id);
public void Lock(string InsideRoomName);
}
I may be making some false assumptions here regarding what is and is not best practices with respect to REST API design, so any guidance there is appreciated as well.
See Question&Answers more detail:
os