Gostaria de saber como você implementaria o seguinte caso de uso no REST. É possível, sem comprometer o modelo conceitual?
Leia ou atualize vários recursos no escopo de uma única transação. Por exemplo, transfira US $ 100 da conta bancária de Bob para a conta de John.
Tanto quanto posso dizer, a única maneira de implementar isso é trapacear. Você pode POSTAR para o recurso associado a John ou Bob e executar toda a operação usando uma única transação. Para mim, isso interrompe a arquitetura REST, porque você essencialmente encapsula uma chamada RPC através do POST, em vez de realmente operar com recursos individuais.
Existem alguns casos importantes que não são respondidos por esta pergunta, o que eu acho muito ruim, porque ele tem uma classificação alta no Google para os termos de pesquisa :-)
Especificamente, um bom propriamente seria: Se você POSTAR duas vezes (porque algum cache está oculto no intermediário), não deverá transferir a quantidade duas vezes.
Para chegar a isso, você cria uma transação como um objeto. Isso pode conter todos os dados que você já conhece e colocar a transação em um estado pendente.
Depois de ter essa transação, você pode confirmar, algo como:
Observe que várias colocações não importam neste momento; mesmo um GET no txn retornaria o estado atual. Especificamente, o segundo PUT detectaria que o primeiro já estava no estado apropriado e apenas o retornaria - ou, se você tentar colocá-lo no estado "reversão" depois que ele já estiver no estado "confirmado", você receberá um erro e a transação confirmada real de volta.
Desde que você fale com um único banco de dados ou com um monitor de transações integrado, esse mecanismo funcionará realmente bem. Além disso, você pode introduzir tempos limites para transações, que você pode expressar usando os cabeçalhos Expira, se quiser.
fonte
Em termos REST, recursos são substantivos que podem ser usados com verbos CRUD (criar / ler / atualizar / excluir). Como não há verbo "transferir dinheiro", precisamos definir um recurso de "transação" que possa ser usado com o CRUD. Aqui está um exemplo em HTTP + POX. O primeiro passo é criar (método HTTP POST) uma nova transação vazia :
Isso retorna um ID da transação, por exemplo, "1234" e de acordo com a URL "/ transaction / 1234". Observe que disparar esse POST várias vezes não criará a mesma transação com vários IDs e também evitará a introdução de um estado "pendente". Além disso, o POST nem sempre pode ser idempotente (um requisito REST), portanto, geralmente é uma boa prática minimizar os dados nos POSTs.
Você pode deixar a geração de um ID de transação para o cliente. Nesse caso, você POST / transaction / 1234 para criar a transação "1234" e o servidor retornará um erro se ele já existir. Na resposta de erro, o servidor pode retornar um ID não utilizado no momento com um URL apropriado. Não é uma boa ideia consultar o servidor em busca de um novo ID com um método GET, pois o GET nunca deve alterar o estado do servidor, e a criação / reserva de um novo ID alterará o estado do servidor.
Em seguida, atualizamos (método HTTP PUT) a transação com todos os dados, comprometendo-a implicitamente:
Se uma transação com o ID "1234" já tiver sido PUT, o servidor fornecerá uma resposta de erro, caso contrário, uma resposta OK e um URL para visualizar a transação concluída.
NB: em / account / john, "john" deve realmente ser o número da conta exclusiva de John.
fonte
Ótima pergunta, o REST é explicado principalmente com exemplos semelhantes a bancos de dados, nos quais algo é armazenado, atualizado, recuperado e excluído. Existem alguns exemplos como este, em que o servidor deve processar os dados de alguma maneira. Não acho que Roy Fielding tenha incluído alguma em sua tese, que foi baseada em http, afinal.
Mas ele fala sobre "transferência de estado representacional" como uma máquina de estado, com links passando para o próximo estado. Dessa maneira, os documentos (as representações) controlam o estado do cliente, em vez de o servidor precisar fazê-lo. Dessa forma, não há estado do cliente, apenas o estado em que link você está.
Eu estive pensando sobre isso, e me parece razoável que, para que o servidor processe algo para você, ao fazer o upload, o servidor criará automaticamente recursos relacionados e fornecerá os links para eles (na verdade, não precisa criá-los automaticamente: ele pode apenas informar os links e apenas criá-los quando e se você os seguir - criação lenta). E também fornecer links para criar novos recursos relacionados - um recurso relacionado possui o mesmo URI, mas é mais longo (adiciona um sufixo). Por exemplo:
/transaction
Glitches fará com que vários recursos sejam criados, cada um com um URI diferente./transaction/1234/proposed
,/transaction/1234/committed
É semelhante à maneira como as páginas da web operam, com a página final dizendo "você tem certeza de que deseja fazer isso?" Essa página da web final é ela mesma uma representação do estado da transação, que inclui um link para ir para o próximo estado. Não apenas transações financeiras; também (por exemplo) a visualização e confirmada na wikipedia. Eu acho que a distinção no REST é que cada estágio na sequência de estados tem um nome explícito (seu URI).
Nas transações / vendas da vida real, geralmente existem documentos físicos diferentes para os diferentes estágios de uma transação (proposta, pedido, recibo etc.). Ainda mais para comprar uma casa, com liquidação etc.
OTOH É como jogar semântica para mim; Fico desconfortável com a nominalização da conversão de verbos em substantivos para torná-lo RESTful, "porque usa substantivos (URIs) em vez de verbos (chamadas RPC)". ou seja, o substantivo "recurso de transação confirmada" em vez do verbo "confirmar esta transação". Eu acho que uma vantagem da nominalização é que você pode se referir ao recurso pelo nome, em vez de precisar especificá-lo de outra maneira (como manter o estado da sessão, para que você saiba o que é "essa transação" ...)
Mas a questão importante é: quais são os benefícios dessa abordagem? ie De que maneira esse estilo REST é melhor que o estilo RPC? Uma técnica excelente para páginas da Web também é útil para processar informações, além de armazenar / recuperar / atualizar / excluir? Eu acho que o principal benefício do REST é a escalabilidade; um aspecto disso não é a necessidade de manter o estado do cliente explicitamente (mas torná-lo implícito no URI do recurso e os próximos estados como links em sua representação). Nesse sentido, ajuda. Talvez isso ajude em camadas / pipelining também? OTOH, apenas um usuário analisará sua transação específica; portanto, não há vantagem em armazená-la em cache para que outros possam lê-la, a grande vitória do http.
fonte
Se você recuar para resumir a discussão aqui, é bastante claro que o REST não é apropriado para muitas APIs, principalmente quando a interação cliente-servidor é inerentemente estável, como ocorre com transações não triviais. Por que pular todas as etapas sugeridas, tanto para o cliente quanto para o servidor, a fim de seguir pedanticamente algum princípio que não se encaixa no problema? Um princípio melhor é fornecer ao cliente a maneira mais fácil, natural e produtiva de compor com o aplicativo.
Em resumo, se você realmente está realizando muitas transações (tipos, não instâncias) em seu aplicativo, não deve criar uma API RESTful.
fonte
Eu me afastei deste tópico por 10 anos. Voltando, não posso acreditar na religião que se disfarça de ciência em que você mergulha quando descansa no Google + confiável. A confusão é mítica.
Eu dividiria essa pergunta ampla em três:
Isso é importante porque permite que todas as solicitações subsequentes sejam totalmente idempotentes, no sentido de que, se forem repetidas n vezes, retornam o mesmo resultado e não fazem mais nada acontecer. O servidor armazena todas as respostas no ID da ação e, se vir a mesma solicitação, repetirá a mesma resposta. Um tratamento mais completo do padrão está neste documento do google . O documento sugere uma implementação que, acredito (!), Siga amplamente os princípios do REST. Especialistas certamente vão me dizer como isso viola os outros. Esse padrão pode ser útil para qualquer chamada não segura ao seu serviço da web, independentemente de haver ou não transações a jusante envolvidas.
Sua exigência é fundamental. Não deixe que as pessoas lhe digam que sua solução não é kosher. Julgue suas arquiteturas à luz de quão bem e de maneira simples elas tratam do seu problema.
fonte
Você precisaria rolar seu próprio tipo de "ID da transação" do gerenciamento de TX. Seriam 4 chamadas:
Você precisaria lidar com o armazenamento das ações em um banco de dados (se a carga balanceada) ou na memória ou algo assim, manipular a confirmação, a reversão e o tempo limite.
Não é realmente um dia de descanso no parque.
fonte
Penso que, neste caso, é totalmente aceitável quebrar a pura teoria do REST nesta situação. De qualquer forma, não acho que exista algo realmente no REST que diga que você não pode tocar em objetos dependentes em casos de negócios que exigem isso.
Eu realmente acho que não vale a pena os bastidores extras pelos quais você pularia para criar um gerenciador de transações personalizado, quando você poderia simplesmente aproveitar o banco de dados para fazer isso.
fonte
Antes de mais nada, transferir dinheiro não é algo que você não pode fazer em uma única chamada de recurso. A ação que você deseja fazer é enviar dinheiro. Então você adiciona um recurso de transferência de dinheiro à conta do remetente.
Feito. Você não precisa saber que esta é uma transação que deve ser atômica etc. Você apenas transfere dinheiro, também conhecido como. envie dinheiro de A para B.
Mas para os casos raros aqui uma solução geral:
Se você deseja fazer algo muito complexo envolvendo muitos recursos em um contexto definido, com muitas restrições que realmente atravessam a barreira o quê versus por que (negócios versus conhecimento de implementação), é necessário transferir o estado. Como o REST deve ser sem estado, você como cliente precisa transferir o estado.
Se você transferir o estado, precisará ocultar as informações internas do cliente. O cliente não deve conhecer informações internas necessárias apenas pela implementação, mas não carrega informações relevantes em termos de negócios. Se essas informações não tiverem valor comercial, o estado deve ser criptografado e uma metáfora como token, passe ou algo precisa ser usado.
Dessa maneira, pode-se passar o estado interno e, usando a criptografia e a assinatura do sistema, ainda pode estar seguro e seguro. Encontrar a abstração certa para o cliente por que ele repassa informações de estado é algo que depende do design e da arquitetura.
A solução real:
Lembre-se de que o REST está falando HTTP e HTTP vem com o conceito de uso de cookies. Esses cookies geralmente são esquecidos quando as pessoas falam sobre a API REST, fluxos de trabalho e interações que abrangem vários recursos ou solicitações.
Lembre-se do que está escrito na Wikipedia sobre cookies HTTP:
Então, basicamente, se você precisar passar o estado, use um cookie. Ele foi projetado exatamente pela mesma razão, é HTTP e, portanto, é compatível com o REST por design :).
A melhor solução:
Se você fala sobre um cliente executando um fluxo de trabalho envolvendo várias solicitações, geralmente fala sobre protocolo. Toda forma de protocolo vem com um conjunto de condições prévias para cada etapa potencial, como a etapa A antes de você executar a B.
Isso é natural, mas expor o protocolo aos clientes torna tudo mais complexo. Para evitá-lo, pense no que fazemos quando precisamos fazer interações e coisas complexas no mundo real. Nós usamos um agente.
Usando a metáfora do agente, você pode fornecer um recurso que pode executar todas as etapas necessárias para você e armazenar as atribuições / instruções reais em que está atuando em sua lista (para que possamos usar o POST no agente ou em uma 'agência').
Um exemplo complexo:
Comprando uma casa:
Você precisa provar sua credibilidade (como fornecer suas anotações policiais), garantir detalhes financeiros, comprar a casa real usando um advogado e um terceiro confiável armazenando os fundos, verificar se a casa agora pertence a você e adicione os itens de compra aos seus registros fiscais etc. (apenas como exemplo, algumas etapas podem estar erradas ou o que for).
Essas etapas podem levar vários dias para serem concluídas, algumas podem ser realizadas em paralelo etc.
Para fazer isso, basta atribuir ao agente a tarefa de comprar uma casa como:
Feito. A agência envia de volta uma referência para você que você pode usar para ver e rastrear o status desse trabalho, e o restante é feito automaticamente pelos agentes da agência.
Pense em um rastreador de erros, por exemplo. Basicamente, você relata o bug e pode usar o ID do bug para verificar o que está acontecendo. Você pode até usar um serviço para ouvir as alterações desse recurso. Missão Concluída.
fonte
Você não deve usar transações do lado do servidor no REST.
Uma das restrições do REST:
A única maneira RESTful é criar um log de refazer transações e colocá-lo no estado do cliente. Com as solicitações, o cliente envia o log de refazer e o servidor refaz a transação e
Mas talvez seja mais simples usar uma tecnologia baseada em sessão de servidor que suporte transações do lado do servidor.
fonte
Acredito que seria o caso de usar um identificador exclusivo gerado no cliente para garantir que o soluço de conexão não implique em uma duplicidade salva pela API.
Eu acho que usar um campo GUID gerado pelo cliente junto com o objeto de transferência e garantir que o mesmo GUID não fosse reinserido novamente seria uma solução mais simples para o assunto da transferência bancária.
Não conheça cenários mais complexos, como reservas de passagens aéreas múltiplas ou micro arquiteturas.
Encontrei um artigo sobre o assunto, relacionando as experiências de lidar com a atomicidade da transação nos serviços RESTful .
fonte
No caso simples (sem recursos distribuídos), você pode considerar a transação como um recurso, em que o ato de criá-la atinge o objetivo final.
Portanto, para transferir entre
<url-base>/account/a
e<url-base>/account/b
, você pode postar o seguinte em<url-base>/transfer
.Isso criaria um novo recurso de transferência e retornaria o novo URL da transferência - por exemplo
<url-base>/transfer/256
.No momento da postagem bem-sucedida, a transação 'real' é realizada no servidor e o valor removido de uma conta e adicionado a outra.
Isso, no entanto, não cobre uma transação distribuída (se, digamos, 'a' for mantido em um banco atrás de um serviço e 'b' em outro banco atrás de outro serviço) - além de dizer "tente frase todos operações de maneira que não exijam transações distribuídas ".
fonte
Eu acho que você pode incluir o TAN na URL / recurso:
Apenas uma ideia.
fonte