Agora vamos começar com a nossa implementação. Para o nosso exemplo, usaremos um aplicativo simples de carrinho de compras.

Crie as classes modelo

No projeto que criamos anteriormente, crie as seguintes classes na pasta Modelos.


public class Product
{
   public int Product_Id { get; set; }
   public string Product_Code { get; set; }
   public string Product_Name { get; set; }
   public double Product_Price { get; set; }
}
public class Order
{
   public int Order_Id { get; set; }
   public List Products { get; set; }
}
public class KeyStore
{
   public string Key { get; set; }
   public DateTime Expiry { get; set; }
}

Embora as classes de produtos e pedidos sejam normalmente usadas em um aplicativo de carrinho de compras, a classe Keystore é usada aqui para armazenar nossas teclas de idempotência. Nesta implementação, salvaremos essas chaves no banco de dados (DBContext). Naturalmente, você pode alterar a implementação para armazenar as chaves no cache ou em qualquer outro armazenamento de dados.

Crie a classe controladora

Clique com o botão direito do mouse na pasta dos controladores na janela Solution Explorer e crie um controlador de API chamado OrderController. Agora, digite o seguinte método de ação na classe OrderController. Este método cria um novo pedido.


(HttpPost)
public IActionResult CreateOrder((FromBody) Order order, (FromHeader(Name = "X-Idempotency_Key")) string key)
{
    if (string.IsNullOrEmpty(key))
    {
        return BadRequest("Idempotency key is required.");
    }
    if (_dbContext.KeyStore.FirstOrDefault(k => k.Key == key)!= null)
    {
        var existingItem = _dbContext.Orders.FirstOrDefault(o => o.Order_Id == order.Order_Id);
        return Conflict(new { message = "Request has already been processed.", item = existingItem });
    }
    _dbContext.KeyStore.Add(new KeyStore {Key = key, Expiry = DateTime.Now.AddDays(7)});
    _dbContext.Add(order);
    _dbContext.SaveChanges();
    return Ok(order.Order_Id);
}

Examine o código acima. Uma chave de idempotência é gerada no lado do cliente e passada no cabeçalho da solicitação. Essa chave será usada pelo servidor para garantir que as chamadas repetidas para o mesmo método de ação não criem registros duplicados no banco de dados. Em outras palavras, se a chave já estiver presente na Keystore, a solicitação de criação do recurso será ignorada. A presença da chave no keystore significa que a solicitação já foi processada anteriormente.

Takeaways

Ao abraçar a idempotência, você pode criar APIs robustas, confiáveis ​​e tolerantes a falhas. As APIs idempotentes são particularmente importantes e benéficas em sistemas distribuídos, onde os problemas de rede podem levar a um grande número de solicitações de tentativa do lado do cliente. Dito isto, você deve sempre validar dados de entrada para garantir a consistência dos dados antes de armazenar dados no banco de dados.