Подтвердить что ты не робот

Как маршрутизировать действия, отличные от CRUD, в веб-API RESTful ASP.NET?

Я пытаюсь создать веб-API RESTful для нашей службы с помощью ASP.NET Web API. У меня возникают проблемы с выяснением того, как направлять действия, отличные от CRUD, на правильное действие контроллера. Пусть мой ресурс - это дверь. Я могу сделать все знакомые вещи CRUD с моей дверью. Скажем, эта модель для моей двери:

public class Door
{
   public long Id { get; set; }
   public string InsideRoomName { get; set; }
   public string OutsideRoomName { get; set; }
}

Я могу выполнять все стандартные операции CRUD через мой веб-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

и т.д. Там, где я столкнулся с трудностями, мне нужно смоделировать действия, не связанные с CRUD, против моей двери. Я хочу смоделировать глагол Lock and Unlock против моего ресурса. Чтение через статей ASP.NET кажется, что руководство переключается на вызов стиля RPC при использовании пользовательских действий. Это дает мне путь:

PUT: http://api.contoso.com/v1/doors/1234/lock
PUT: http://api.contoso.com/v1/doors/1234/unlock

Это, похоже, противоречит духу REST, который направлен на путь указания ресурса. Полагаю, я мог бы моделировать глагол как ресурс:

POST: http://api.contoso.com/v1/doors/1234/lockrequests
POST: http://api.contoso.com/v1/doors/1234/unlockrequests

В этом случае я все еще мог бы использовать рекомендацию {controller}/{id}/{action}, но похоже, что я все еще создаю смешанный API RPC/REST. Возможно ли, или даже рекомендовано, насколько подходят интерфейсы REST, для внесения пользовательского действия в список параметров?

PUT: http://api.contoso.com/v1/doors/1234?lock
PUT: http://api.contoso.com/v1/doors/1234?unlock

Я мог предвидеть необходимость поддерживать этот вызов с параметрами запроса, например:

PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria

Как мне создать маршрут для сопоставления этого запроса с моим 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);
}

Я могу сделать некоторые ложные предположения здесь относительно того, что является и не является наилучшей практикой в ​​отношении дизайна REST API, поэтому любое руководство там также оценено.

4b9b3361

Ответ 1

Чтобы обработать сценарий lock/unlock, вы можете рассмотреть возможность добавления свойства State в объект Door:

   public State State { get; set; }

где State - это перечисление доступных значений, например.

{
LockedFromOutsideRoom,
LockedFromInsideRoom,
Open
}

Чтобы уточнить: то, что вы добавляете состояние к объекту, не противоречит принципам покоя, поскольку состояние передается через api каждый раз, когда вы делаете вызов, чтобы что-то сделать с дверью.

Затем через api вы отправите запрос PUT/POST для изменения состояния двери при каждой блокировке/разблокировке. Сообщение, вероятно, будет лучше, поскольку обновляется только одно свойство:

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

Ответ 2

Из принципа RESTful, возможно, лучше всего ввести свойство статуса для управления этими действиями, отличными от CURD. Но я не думаю, что он соответствует реальному развитию производства.

Каждый ответ на этот вопрос выглядит так, как будто вам нужно использовать обход, чтобы обеспечить, чтобы ваш дизайн API соответствовал RESTful. Но я обеспокоен тем, что действительно делает удобство для пользователя и разработчика?

взглянем на дизайн API3.0 в Google bloger: https://developers.google.com/blogger/docs/3.0/reference, используя URL-адрес лота для действий, отличных от CURD.

И это интересно,

POST  /blogs/blogId/posts/postId/comments/commentId/spam

и описание

Отмечает комментарий как спам. Это установит статус комментария для спама и спрячет его в рендеринг комментариев по умолчанию.

Вы можете видеть, что комментарий имеет статус, указывающий, является ли он спамом или нет, но он не был разработан как ответ, упомянутый выше JoannaTurban.

Я думаю, с точки зрения пользователя, это более удобно. Не нужно заботиться о структуре и значении перечисления "статус". И на самом деле вы можете добавить много атрибутов в определение "статус", например "isItSpam", "isItReplied", "isItPublic" и т.д. Дизайн будет недружественным, если в статусе много вещей.

По некоторым требованиям бизнес-логики, чтобы использовать легко понятный глагол, вместо того чтобы пытаться сделать его полностью "реальным" RESTful, он более продуктивен для пользователя и разработчика. Это мое мнение.

Ответ 3

С точки зрения REST вы, вероятно, захотите рассматривать блокировку как ресурс сами по себе. Таким образом вы создаете и удаляете замок независимо от двери (хотя предположительно найдите конечную точку блокировки из представления двери). URL-адрес ресурса, вероятно, будет связан с URL-адресом двери, однако с точки зрения RESTful это не имеет значения. REST - это отношения между ресурсами, поэтому важной частью является то, что URL-адрес блокировки можно обнаружить из представления двери.