Por favor, acerte uma discussão entre mim e um amigo.
No momento, estamos projetando uma API do produto. Nossa entidade de produto se parece com isso
{
"Id": "",
"ProductName": "",
"StockQuantity": 0
}
As vendas dos produtos são realizadas por terceiros e são obrigadas a nos informar a quantidade comprada para que o StockQuantity
campo possa ser diminuído.
Minha abordagem:
PUT /api/Product/{Id}/ --data { "StockQuantity": "{NewStockQuantity}" }
O terceiro é responsável por consultar o produto, fazer o cálculo com base na StockQuantity
quantidade atual e adquirida e enviar uma PUT
solicitação com o novo valor.
Meu amigo não quer que terceiros façam o cálculo. A abordagem dele
PUT /api/Product/{Id}/DecreaseStock --data { "PurchasedQuantity": "{PurchasedQuantity}" }
Para que possamos fazer o cálculo e atualizar o StockQuantity
Não quero criar pontos de extremidade baseados em funções e ele não deseja confiar em terceiros para fazer os cálculos.
Qual seria a maneira correta de abordar esse problema?
fonte
Respostas:
Você pode permitir que seus terceiros publiquem o seu produto. Por exemplo:
Concordo com o seu ponto e com o do seu colega. Essa é a lógica de negócios e não deve ser deixada para o cliente da API, mas você também deve evitar ter "funções" como pontos de extremidade.
Às vezes, resolver esses problemas é tão fácil quanto chamá-lo de maneira diferente, reconhecidamente nem sempre.
fonte
/sale
terminal ainda é válida?/sale
e/product/{id}/sale
são completamente independentes e o fato de terem nomes semelhantes não implica, de forma alguma, que eles se refiram ao mesmo recurso.sale
não está no meu domínio e não faz parteproduct
. Ainda faz sentido criar/product/{id}/sale
enquanto não representa nenhum recurso real?Não há razão para que você também não possa fazer; ou ambos.
Em um contexto de ponto de venda, o rastreamento de transações individuais faz muito sentido. Lá, a solução de Robert faz muito sentido.
No contexto de estoque / armazém, você não controla necessariamente as transações, mas "faz o inventário"; ter um terminal que permita ao cliente relatar seus níveis de estoque
faz muito sentido.
Os níveis de estoque mudam por outros motivos que não "vendas"; Apenas algo para ter em mente.
Em teoria, o nível de estoque deve ser computável a partir das mudanças; mas em alguns domínios, essa é precisamente a suposição que você deseja verificar . Você deseja calcular o nível de estoque de duas maneiras diferentes e verificar discrepâncias (também conhecido como "encolhimento").
Portanto, não acho que a semântica seja clara, com base no contexto que você forneceu.
Quanto à parte HTTP;
PUT [target-uri]
faz sentido semanticamente quando você está substituindo uma representação de um documento por outra. É umUPSERT
- o segundo PUT para um recurso está pedindo para substituir a representação existente.diz que a quantidade de unidades vendidas
3
não é10
.É assim que
10
pareceEssa é outra maneira de ortografia
10
.No que diz respeito ao HTTP, isso também é aceitável. No entanto, não é uma ótima opção em uma rede não confiável porque as mensagens às vezes são duplicadas.
É isso
13
? ou10
?Isso é inequivocamente
10
Isso é inequivocamente
10
Isso é inequivocamente
13
Isso é inequivocamente
13
10
13
(Para ser justo, o HTTP tem suporte para solicitações condicionais ; você pode elevar alguns dos metadados do protocolo específico do domínio para os cabeçalhos agnósticos do domínio para eliminar parte da ambiguidade - se conseguir convencer o cliente a seguir adiante).
Obviamente, existem trocas - o HTML não tem suporte nativo a PUT; se você pretende que os clientes da sua API sejam navegadores, é necessário um protocolo baseado no POST ou extensões de código sob demanda para converter o envio do formulário de um POST para um PUT.
fonte
Parece um design muito ruim, não importa como você o corta. Eu nunca confiaria a terceiros para me informar o inventário atual, a menos que eu os contratasse para gerenciar meu armazém.
Além disso, a abordagem de aparência de função não é RESTful e deve criar consternação entre seus consumidores.
Por fim, não consigo imaginar um cenário em que a única coisa que você se preocupa com uma venda é o inventário resultante que resta depois que ela é concluída.
É muito melhor que terceiros publiquem um recurso de Venda ou Fatura para você (com informações sobre qual produto, quantidade, data, método de envio, informações do cliente etc.). Isso permite que você faça análises e rastreamentos reais do que você está vendendo, para quem, quando, etc., para que você possa realmente planejar seus negócios.
Mesmo se seu terceiro estiver realizando o atendimento total do pedido, você desejará acompanhar as vendas para fins contábeis e demográficos dos clientes, se nada mais.
fonte
Esse tipo de design tem um problema importante: se você quiser ter mais de um encadeamento de cliente em execução na sua API, estará sujeito a leituras / gravações sujas. Ou seja, entre o momento em que o cliente reduz a quantidade atual e calcula o novo valor, outro cliente pode obter o mesmo valor anterior e calcular uma resposta diferente. A quantidade que você terminar será a que for atualizada por último, mas nenhuma estiver correta. Por exemplo, digamos que sua quantidade atual seja 10. O cliente A deseja vender 5 itens e extrai a quantidade atual. Ao mesmo tempo, o cliente B deseja vender 6 itens e extrai a quantidade atual. Ambos vêem 10 itens em estoque. A calcula 5 itens restantes. Bcalcula 4 restantes. Ambos são atualizados. Agora você mostra 4 ou 5 itens restantes, dependendo de quem foi a última atualização registrada. No entanto, você realmente vendeu mais itens do que realmente possui. O pior é que não há maneira fácil de percorrer e ver o que deu errado. Tudo o que você tem são dois incorretos
PUTs
em seus logs para examinar.Em qualquer sistema de registro do mundo real, simplesmente ter um total atual não é adequado. Considere se você for a uma loja e comprar vários itens. Você pede um recibo e o caixa apenas entrega um recibo com um único total. Como você mostraria que o total está correto com esse recibo? Como você mostraria que comprou um item se quisesse devolver algo?
A abordagem do seu amigo é melhor, mas eu sugiro adicionar um ID de transação ao mix. Isso aborda as preocupações reais mencionadas pelo VoiceOfUnreason sobre transações duplicadas. Uma opção é fornecer uma
POST
operação para criar uma nova transação e, em seguida,PUT
confirmar a transação. No momento da confirmação, você reduz o estoque total ou nega a solicitação, porque não há disponibilidade suficiente.fonte
Como as vendas são realizadas por terceiros, você precisa ter controle sobre o estoque do produto, não permitindo que eles atualizem a contagem de estoque.
Para uso interno, por exemplo, para fins de contagem de estoque, você pode ter sua abordagem, por exemplo
PUT /api/Product/{Id}/ --data { "StockQuantity": "{NewStockQuantity}" }
.Para uso externo, é necessário criar uma interface separada, por exemplo,
/api/SalesOrder/
que obtenha uma lista de produtos e quantidades, como:Com base no
SalesOrder
envio de terceiros, a quantidade de cada produto pode ser atualizada e atribuída ao pedido ou você pode rejeitá-lo se não houver produto suficiente disponível.O processamento e a contagem de estoques são processos internos. Terceiros exigem apenas interface para que possam encaminhar seus pedidos ao estoque. Basicamente,
SalesOrder
é assim que as Vendas, Finanças e Armazém se comunicam para concluir uma venda.fonte