Como criar uma API REST para manipular operações não CRUD?

11

Estou tentando converter um conjunto de serviços baseados em SOAP em uma API RESTful.

Comecei identificando recursos analisando os nomes das operações e obtive o recurso Subscription.

Quando preciso atualizar o estado da assinatura, não posso simplesmente enviar uma POSTsolicitação ao servidor, porque não tenho acesso direto aos recursos, mas preciso chamar algumas operações no estilo RPC para atualizar suas propriedades. Além disso, somente e somente se eu estiver alterando o estado da assinatura para "ativo", será necessária uma chamada adicional para um serviço externo.

Nesses casos, qual é a melhor prática para lidar com operações subjacentes?

A solução que eu encontrei é usar parâmetros de consulta, para que, se eu precisar chamar o serviço de ativação, possa usar algo como:

POST /subscriptions/{subscriptionid}/?activate=true

Considerando que não posso atualizar diretamente meus campos de objeto de inscrição, existe alguma prática recomendada para lidar com esse tipo de conversão?

Atualização 1:

Eu posso colocar no corpo da minha solicitação POST alguns valores, por exemplo "state": "active"

e verificar dentro do meu serviço as operações adequadas a serem acionadas.

Vektor88
fonte
O mapeamento de comandos do REST para verbos HTTP falha com operações complexas. Você está melhor fora apenas fazendo uma chamada estilo RPC POST activateSubscription / {id} ninguém vai ser confundido por ele
Ewan
@ Ewan Não tenho certeza de que isso esteja em conformidade com o modelo RESTful, mas criei outra solução: no meu código, posso chamar a operação apropriada no estilo RPC de acordo com a carga de entrada (posso passar state = active no corpo do meu pedido post, o código irá chamar o código de ativação)
Vektor88
1
Uma atualização para um recurso existente como esse deve ser um PATCH, e o corpo da consulta é um modelo parcial do que você está alterando. Um POST deve ser uma solicitação que cria um recurso. Essa distinção, além de ser mais clara para o usuário, facilitará o código saber quando esta operação está acontecendo, em vez de uma publicação de recurso.
Sr. Cochese
1
@ Vektor88 Normalmente, mas essas são operações idempotentes nas quais você precisa passar toda a representação do estado do recurso. Esse caso de uso parece muito mais com uma atualização parcial, que se ajusta muito bem a um PATCH.
Sr. Cochese
1
@MrCochese POST não é idempotente.
JimmyJames

Respostas:

8

Você precisa assistir a essa palestra de Jim Webber.

Quando preciso atualizar o estado da assinatura, não posso simplesmente enviar uma solicitação POST ao servidor, porque não tenho acesso direto aos recursos, mas preciso chamar algumas operações no estilo RPC para atualizar suas propriedades. Além disso, somente e somente se eu estiver alterando o estado da assinatura para "ativo", será necessária uma chamada adicional para um serviço externo.

Pense em "mensagens"; envie uma mensagem para o seu domínio, descrevendo o que você deseja que aconteça. O efeito colateral da mensagem é que seu modelo de domínio realmente altera seu estado. O "recurso" é a fila de mensagens.

POST /subscriptions/{subscriptionid}/?activate=true

A ortografia do nome do recurso não importa para as máquinas; mas as pessoas tendem a ficar exigentes quando os identificadores que você usa quebram da convenção de que recursos são "substantivos".

Além disso, estamos falando de um recurso subordinado /subscriptions/{subscriptionid}, portanto, a convenção (consulte a RFC 3986 ) exige expressar esse relacionamento com um segmento de caminho, em vez de usar a parte da consulta.

Portanto, essas grafias podem ser razoáveis

POST /subscriptions/{subscriptionid}/messages
POST /subscriptions/{subscriptionid}/activations
VoiceOfUnreason
fonte
1
A palestra de Jim Webber está disponível em youtube.com/watch?v=aQVSzMV8DWc
user674669
0

Se for um sinalizador booleano para ativar / desativar coisas, eu diria que o padrão é usar JSON:

POST /subscriptions/{subscriptionid}/
{
    format: 0,
    subscription: 
    {
        active: false
    }
}

Isso é facilmente estendido se você deseja oferecer suporte a mais propriedades. Outra abordagem está fornecendo seu próprio terminal:

POST /subscriptions/{subscriptionid}/active/
DELETE /subscriptions/{subscriptionid}/active/

Pessoalmente, eu usaria isso apenas se o activeestado desse evento precisar / tiver propriedades que você possa passar / obter no JSON, como um ID de usuário ou configuração.

Se não for um valor booleano, mas apenas uma ação que você precisa disparar, mas não precisa / possui nenhum feedback de status (exceto um OK imediato 200), eu usaria um ponto de extremidade como esse para acioná-lo como um RPC:

POST /subscriptions/{subscriptionid}/activate/

Em caso de dúvida, leia o seguinte: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful (consulte "E as ações que não se encaixam no mundo das operações CRUD? ")

Barry Staes
fonte
0

O REST não é funcional. Activateé um verbo e não pode ser um estado, Activeé um estado.

Como o RESTful não é funcional, você não pode dizer ao serviço RESTful o que fazer, mas pode adicionar trabalho para a fila de um serviço.

Veja isso:

PUT /subscriptionQueue
subscriptionId={subscriptionId}
active=true

Esta solicitação é RESTful e suporta todos os benefícios do RESTful (como desempenho, ácido ...)

Peter Rader
fonte