Neste artigo, o autor afirma que
Às vezes, é necessário expor uma operação na API que inerentemente não seja RESTful.
e essa
Se uma API tiver muitas ações, isso indica que ela foi projetada com um ponto de vista RPC em vez de usar os princípios RESTful ou que a API em questão é naturalmente mais adequada para um modelo de tipo RPC.
Isso reflete o que li e ouvi em outros lugares também.
No entanto, acho isso bastante confuso e gostaria de entender melhor o assunto.
Exemplo I: Desligando uma VM por meio de uma Interface REST
Acho que existem duas maneiras fundamentalmente diferentes de modelar o desligamento de uma VM. Cada caminho pode ter algumas variações, mas vamos nos concentrar nas diferenças mais fundamentais por enquanto.
1. Corrija a propriedade de estado do recurso
PATCH /api/virtualmachines/42
Content-Type:application/json
{ "state": "shutting down" }
(Como alternativa, PUT
no sub-recurso /api/virtualmachines/42/state
.)
A VM será desligada em segundo plano e, em algum momento posterior, dependendo de o desligamento ter êxito ou não, o estado poderá ser atualizado internamente com "desligamento".
2. PUT ou POST na propriedade de ações do recurso
PUT /api/virtualmachines/42/actions
Content-Type:application/json
{ "type": "shutdown" }
O resultado é exatamente o mesmo que no primeiro exemplo. O estado será atualizado para "desligar" imediatamente e, eventualmente, para "desligar".
Os dois projetos são RESTful?
Qual design é melhor?
Exemplo II: CQRS
E se tivermos um domínio CQRS com muitas dessas "ações" (também conhecidas como comandos) que podem levar a atualizações de vários agregados ou não podem ser mapeadas para operações CRUD em recursos e sub-recursos concretos?
Devemos tentar modelar tantos comandos quanto concreto criar ou atualizar recursos concretos, sempre que possível (seguindo a primeira abordagem do exemplo I) e usar "pontos finais de ação" para o resto?
Ou devemos mapear todos os comandos para os pontos de extremidade de ação (como na segunda abordagem do exemplo I)?
Onde devemos traçar a linha? Quando o design se torna menos RESTful?
Um modelo CQRS é mais adequado para uma API RPC como a API?
De acordo com o texto citado acima, é, como eu o entendo.
Como você pode ver nas minhas muitas perguntas, estou um pouco confuso sobre esse tópico. Você pode me ajudar a entender melhor?
fonte
Respostas:
No primeiro caso (desligamento de VMs), eu consideraria nenhuma das alternativas de OP RESTful. É verdade que, se você usar o modelo de maturidade de Richardson como parâmetro, ambos são APIs de nível 2 porque usam recursos e verbos.
Porém, nenhum deles usa controles hipermídia e, na minha opinião, esse é o único tipo de REST que diferencia o design da API RESTful do RPC. Em outras palavras, permaneça nos níveis 1 e 2 e, na maioria dos casos, você terá uma API no estilo RPC.
Para modelar duas maneiras diferentes de desligar uma VM, eu exporia a própria VM como um recurso que (entre outras coisas) contém links:
Se um cliente desejar desligar o
Ploeh
VM, deve seguir o link com oshut-down
tipo de relacionamento. (Normalmente, conforme descrito no RESTful Web Services Cookbook , você usaria um IRI ou um esquema de identificação mais elaborado para tipos de relacionamento, mas optei por manter o exemplo o mais simples possível.)Nesse caso, há poucas outras informações a serem fornecidas com a ação, portanto, o cliente deve simplesmente fazer um POST vazio em relação à URL no
href
:(Como essa solicitação não tem corpo, seria tentador modelá-la como uma solicitação GET, mas as solicitações GET não devem ter efeitos colaterais observáveis; portanto, o POST é mais correto.)
Da mesma forma, se um cliente quiser desligar a VM, seguirá o
power-off
link.Em outras palavras, os tipos de relacionamento dos links fornecem recursos que indicam a intenção. Cada tipo de relacionamento tem um significado semântico específico. É por isso que às vezes falamos sobre a web semântica .
Para manter o exemplo o mais claro possível, ocultei intencionalmente os URLs em cada link. Quando o servidor de hospedagem recebe a solicitação de entrada, ele saberá que isso
fdaIX
significa desligar eCHTY91
significa de desligamento .Normalmente, eu codificaria a ação no próprio URL, para que os URLs fossem
/vms/1234/shut-down
e/vms/1234/power-off
, mas ao ensinar, isso atrapalha a distinção entre tipos de relacionamento (semântica) e URLs (detalhes de implementação).Dependendo de quais clientes você possui, considere tornar os URLs RESTful não hackáveis .
CQRS
Quando se trata de CQRS, uma das poucas coisas que Greg Young e Udi Dahan concordam é que o CQRS não é uma arquitetura de nível superior . Portanto, eu seria cauteloso ao criar uma API RESTful muito semelhante ao CQRS, porque isso significaria que os clientes se tornariam parte de sua arquitetura.
Freqüentemente, a força motriz por trás de uma API RESTful real (nível 3) é que você deseja evoluir sua API sem interromper os clientes e sem ter o controle dos clientes. Se essa é a sua motivação, o CQRS não seria minha primeira escolha.
fonte
DELETE
me parece estranho, porque depois de desligar o vm ainda existirá, apenas no estado "power off" (ou sth. assim).Desligando uma VM por meio de uma interface REST
Este é realmente um exemplo um pouco famoso, apresentado por Tim Bray em 2009 .
Roy Fielding, discutindo o problema, compartilhou esta observação :
Em resumo, você tem um recurso de informações que retorna uma representação atual do estado monitorado; essa representação pode incluir um link hipermídia para um formulário que solicite uma alteração nesse estado, e o formulário possui outro link para um recurso para manipular (cada) solicitação de alteração.
Seth Ladd teve as principais informações sobre o problema
A programação RESTful é a burocracia Vogon em escala web. Como você faz algo RESTful? Invente uma nova documentação e digitalize a documentação.
Em uma linguagem um pouco mais sofisticada, o que você está fazendo é definir o protocolo de aplicativo de domínio para "desligar uma VM" e identificar os recursos necessários para expor / implementar esse protocolo
Olhando para seus próprios exemplos
Isso está ok; você realmente não está tratando a solicitação em si como seu próprio recurso de informação separado, mas ainda pode gerenciar.
Você perdeu um pouco de sua representação da mudança.
Por exemplo, o tipo de mídia JSON Patch formata instruções como se você estivesse modificando diretamente um documento JSON
Em sua alternativa, a ideia está próxima, mas não obviamente correta.
PUT
é uma substituição completa do estado do recurso no URL de destino ; portanto, você provavelmente não escolheria uma ortografia que se pareça com uma coleção como destino de uma representação de uma única entidade.É consistente com a ficção de que estamos anexando uma ação a uma fila
É consistente com a ficção de que estamos fazendo uma atualização no item de cauda na fila; é um pouco estranho fazer dessa maneira. O princípio da menor surpresa recomenda atribuir a cada PUT seu próprio identificador único, em vez de colocá-las em um único local e modificar vários recursos ao mesmo tempo.
Observe que, na medida em que estamos discutindo, a ortografia do URI-REST não se importa;
/cc719e3a-c772-48ee-b0e6-09b4e7abbf8b
é um URI perfeitamente cromulento no que diz respeito ao REST. A legibilidade, como nos nomes de variáveis, é uma preocupação separada. Usar grafias consistentes com a RFC 3986 tornará as pessoas muito mais felizes.CQRS
Greg Young no CQRS
Dado que você está falando sobre CQRS no contexto de HTTP / REST, parece razoável supor que você esteja trabalhando neste último contexto, então vamos com isso.
Surpreendentemente, este é ainda mais fácil que o seu exemplo anterior. A razão para isso é simples: comandos são mensagens .
Jim Webber descreve o HTTP como o protocolo de aplicação de um escritório da década de 1950; o trabalho é realizado recebendo mensagens e colocando-as nas caixas de entrada. A mesma idéia é válida - obtemos uma cópia em branco de um formulário, preenchemos com as especificidades que conhecemos, entregamos. Ta da
Sim, na medida em que os "recursos concretos" são mensagens, e não entidades no modelo de domínio.
Ideia-chave: sua API REST ainda é uma interface ; você poderá alterar o modelo subjacente sem que os clientes precisem alterar as mensagens. Ao liberar um novo modelo, você libera uma nova versão dos pontos de extremidade da Web que sabem como usar o protocolo de domínio e aplicá-lo ao novo modelo.
Na verdade, não - em particular, os caches da web são um ótimo exemplo de um "modelo de leitura eventualmente consistente". Tornar cada uma das suas visualizações endereçáveis de forma independente, cada uma com suas próprias regras de cache, oferece um monte de dimensionamento gratuitamente. Há relativamente pouco apelo a uma abordagem exclusivamente de RPC para leituras.
Para gravações, é uma pergunta mais complicada: enviar todos os comandos para um único manipulador em um único endpoint ou em uma única família de endpoints é certamente mais fácil . O REST é realmente mais sobre como você encontra a comunicação onde o ponto final está para o cliente.
Tratar uma mensagem como seu próprio recurso exclusivo tem a vantagem de poder usar PUT, alertando os componentes intermediários para o fato de que o tratamento da mensagem é idempotente, para que eles possam participar de certos casos de tratamento de erros. . (Nota: que, do ponto de vista dos clientes, se os recursos tiverem URI diferente, eles serão recursos diferentes; o fato de que todos eles podem ter o mesmo código de manipulador de solicitação no servidor de origem é um detalhe de implementação oculto pelo uniforme interface).
Fielding (2008)
fonte
Você pode aproveitar 5 níveis de tipo de mídia para especificar o comando no campo de cabeçalho do tipo de conteúdo da solicitação.
No exemplo da VM, seria algo nesse sentido
Então
Ou
Consulte https://www.infoq.com/articles/rest-api-on-cqrs
fonte
O exemplo no artigo vinculado baseia-se na idéia de que a inicialização e o desligamento da máquina devem ser direcionados por comandos, e não por alterações no estado dos recursos modelados. O último é praticamente o que o REST vive e respira. Uma melhor modelagem da VM exige uma olhada em como funciona a sua contraparte do mundo real e como você, como humano, interagia com ela. Isso é longo, mas acho que dá uma boa visão do tipo de pensamento necessário para fazer uma boa modelagem.
Existem duas maneiras de controlar o estado de energia do computador na minha mesa:
Para uma VM, ambos podem ser modelados como valores booleanos de leitura / gravação:
power
- Quando alterado paratrue
, nada acontece além de uma anotação de que a chave foi colocada nesse estado. Quando alterada parafalse
, a VM é comandada para um estado de desligamento imediato. Por uma questão de integridade, se o valor for inalterado após uma gravação, nada acontece.onoff
- Quando alterado paratrue
, nada acontece sepower
estiverfalse
, caso contrário, a VM deve iniciar. Quando alterado parafalse
, nada acontece sepower
forfalse
, caso contrário, a VM é comandado para notificar o software para fazer um desligamento ordenado, o que ele vai fazer e, em seguida, notificar o VM que ele pode ir para o poder-fora do estado. Novamente, para ser completo, uma gravação sem alteração não faz nada.Com tudo isso, percebe-se que há uma situação em que o estado da máquina não reflete o estado dos comutadores, e é durante o desligamento.
power
ainda serátrue
eonoff
seráfalse
, mas o processador ainda está sendo desligado e, para isso, precisamos adicionar outro recurso para que possamos saber o que a máquina está realmente fazendo:running
- Um valor somente leitura que étrue
quando a VM está em execução efalse
quando não está, determinado solicitando o estado do hypervisor.O resultado disso é que, se você deseja que uma VM seja inicializada, verifique se os recursos
power
eonoff
foram definidostrue
. (Você pode permitir que apower
etapa seja ignorada, redefinindo-a automaticamente, de modo que, se definida comofalse
,true
ocorrerá após a parada verificável da VM. Se isso é uma coisa RESTfully pura a fazer é forragem para outra discussão.) Se você quer fazer um desligamento ordenado, você defineonoff
afalse
e voltar mais tarde para ver se a máquina realmente parou, definindopower
afalse
se não o fizesse.Como o mundo real, você ainda tem o problema de ser direcionado para iniciar a VM depois que ela foi
onoff
alterada para,false
mas ainda érunning
porque está no meio do desligamento. Como você lida com isso é uma decisão política.fonte
Então, se você quiser pensar tranqüilamente, esqueça os comandos. O cliente não diz ao servidor para desligar a VM. O cliente "encerra" (metaforicamente falando) sua cópia da representação de recurso, atualizando seu estado e, em seguida, coloca essa representação novamente no servidor. O servidor aceita essa nova representação de estado e, como efeito colateral disso, na verdade, desliga a VM. O aspecto do efeito colateral é deixado para o servidor.
É menos
Ei servidor, cliente aqui, você se importaria de desligar a VM
e mais de
Ei, servidor, cliente aqui, atualizei o estado do recurso VM 42 para o estado de desligamento, atualize sua cópia desse recurso e faça o que achar adequado
Como efeito colateral do servidor que aceita esse novo estado, ele pode verificar quais ações ele realmente deve executar (como desligar fisicamente a VM 42), mas isso é transparente para o cliente. O cliente não está preocupado com as ações que o servidor precisa executar para se tornar consistente com esse novo estado
Então esqueça os comandos. Os únicos comandos são os verbos no HTTP para transferência de estado. O cliente não sabe, nem se importa, como o servidor colocará a VM física no estado de desligamento. O cliente não está emitindo comandos para o servidor para conseguir isso, está apenas dizendo: Este é o novo estado, descubra .
O poder disso é que ele desacopla o cliente do servidor em termos de controle de fluxo. Se, posteriormente, o servidor alterar a forma como funciona com VMs, o cliente não se importará. Não há pontos de extremidade de comando para atualizar. No RPC, se você alterar o ponto final da API de
shutdown
para,shut-down
você quebrou todos os seus clientes, pois agora eles não sabem o comando para chamar o servidor.O REST é semelhante à programação declarativa, onde, em vez de listar um conjunto de instruções para alterar algo, você apenas indica como deseja que seja e permite que o ambiente de programação descubra.
fonte
POST /api/virtualmachines/42/shutdown
vez de ter qualquer "efeito colateral". A API deve ser compreensível para o usuário, como vou saber que, por exemploDELETE /api/virtualmachines/42
, desligará a VM? Um efeito colateral para mim é um bug. Devemos projetar nossas APIs para serem compreensíveis e auto-descritivas