Como rotear ações não-CRUD em uma API da Web ASP.NET RESTful?
Eu estou tentando projetar uma API da web RESTful para o nosso serviço usando o ASP.NET Web API. Estou tendo problemas para descobrir como rotear ações não-CRUD para a ação correta do controlador. Vamos supor que meu recurso seja uma porta. Eu posso fazer todas as coisas familiares de CRUD com a minha porta. Vamos dizer que o modelo para minha porta é:
public class Door
{
public long Id { get; set; }
public string InsideRoomName { get; set; }
public string OutsideRoomName { get; set; }
}
Eu posso fazer todas as minhas operações padrão CRUD via minha 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
e assim por diante. Onde eu me deparo com problemas é quando eu preciso modelar as ações não-CRUD contra a minha porta. Eu quero modelar um verbo de bloqueio e desbloqueio contra o meu recurso. Lendo através doArtigos ASP.NET a orientação parece ser mudar para uma chamada de estilo RPC ao usar ações personalizadas. Isso me dá um caminho:
PUT: http://api.contoso.com/v1/doors/1234/lock
PUT: http://api.contoso.com/v1/doors/1234/unlock
Isso parece entrar em conflito com o espírito do REST que aponta para o caminho para indicar um recurso. Eu suponho que eu poderia modelar o verbo como um recurso:
POST: http://api.contoso.com/v1/doors/1234/lockrequests
POST: http://api.contoso.com/v1/doors/1234/unlockrequests
Nesse caso, ainda posso usar a recomendação {controller} / {id} / {action}, mas parece que ainda estou criando uma API RPC / REST mista. É possível, ou mesmo recomendado, no que diz respeito às interfaces REST, colocar a ação personalizada na lista de parâmetros?
PUT: http://api.contoso.com/v1/doors/1234?lock
PUT: http://api.contoso.com/v1/doors/1234?unlock
Eu poderia prever a necessidade de ter essa chamada suportada com parâmetros de consulta, como:
PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria
Como eu criaria a rota para mapear essa solicitação para o meu 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);
}
Eu posso estar fazendo algumas suposições falsas aqui em relação ao que é e não é uma prática recomendada com relação ao design da REST API, portanto, qualquer orientação também é apreciada.