Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
721 views
in Technique[技术] by (71.8m points)

rest - How to Route non-CRUD actions in a RESTful ASP.NET Web API?

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

To handle the lock/unlock scenario you could consider adding a State property to the Door object:

   public State State { get; set; }

where State is an enum of available values, e.g.

{
LockedFromOutsideRoom,
LockedFromInsideRoom,
Open
}

To clarify: That you're adding a state to the object is not against restful principles as the state is passed over the api every time you make a call to do something with the Door.

Then via the api you would send a PUT/POST request to change the state of the Door on each lock/unlock. Post would probably be better as it's only one property that gets updated:

POST: http://api.contoso.com/v1/doors/1234/state
body: {"State":"LockedFromInsideRoom"}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...