Como construir Endpoints de Webhook à prova de falhas?
Um pequeno guia de ajuda para implementação de serviços expostos na internet
No ecossistema de APIs moderno, os Webhooks são uma parte importante da comunicação entre serviços na internet. Seja para processar um pagamento, um cadastro de cliente, ou alguma outra interação cotidiana e frequente. Porém, ao se deparar com uma eventual necessidade de implementar um Webhook, é comum para um minuto e pensar:
Como podemos fazer um Endpoint de Webhook da melhor forma?
Expor um recurso como esse na internet para receber dados externos, traz desafios críticos de segurança e escalabilidade. Com isso, reuni um conteúdo que foi preparado com a idéia de fornecer um olhar sobre os principais pontos de atenção, para quando precisamos expor um serviço na internet.
Controle quem fala com você
Um dos pilares mais importantes quando estamos provendo um serviço desse tipo é a autenticação, ela identifica quem está fazendo a chamada, e tem como objetivo principal garantir que a entidade que está chamando é quem diz ser. Existem diversas formas de autenticação, podemos nos aprofundar em outro momento em como fazer cada uma delas. Aqui vão alguns exemplos:
Chaves de API(API Keys): Geralmente identificam um sistema, um projeto, um servidor que faz a chamada, não necessariamente um usuário final.
Tokens de autenticação(OAuth, JWT, etc…): Identificam o usuário específico que está usando um determinado aplicativo, esses tokens contem dados do usuário como escopo de permissão e são assinados para evitar que sejam manipulados.
Diferente de aplicações com o papel de cliente, os quais realizam a requisição, quando implementamos um endpoint de Webhook, que tem um papel de servidor, isso inverte a lógica de confiança. Saiba mais sobre boas práticas de implementação de clients em Go aqui nesse post.
Responda sempre rápido
Se muita coisa precisar ser feita durante o recebimento da requisição, podemos ter o risco de gerar um timeout no fluxo. A maior parte dos serviços implementam regras rígidas de espera, geralmente entre 5 e 30 segundos no máximo, para que seja retornado uma resposta. O ponto chave é que o processamento da mensagem em si não precisa necessariamente ser realizado antes da resposta do Webhook, podendo ser feito em um fluxo assíncrono através de uma fila. Então temos o seguinte cenário:
Receba a requisição.
Valide a autenticação.
Persista a mensagem em uma fila(RabbitMQ, Redis, SQS, Pub/Sub, etc…)
Retorne imediatamente a resposta com status
202 Acceptedou200 OK
Espere duplicidade
De forma geral, as requisições estão condicionadas a problemas de conexão, como pouca cobertura de rede, aumento na latência de resposta e possíveis timeouts quando houver picos de tráfego. Visando contornar esses problemas, o client costuma implementar políticas de retentativas, para que em casos específicos, uma mensagem que falhou previamente possa ser reenviada. Nosso endpoint de webhook deve ser capaz de lidar com múltiplas retentativas de envio de uma mesma mensagem, aplicando técnicas que garantem a idempotência, como por exemplo:
Tenha um Id único para a mensagem.
Verifique se o Id já foi tratado, se foi, ignore o processamento.
Retorne
200 OKpara o serviço não emitir o envio dessa mensagem novamente.
Monitoramento
Esse é um ponto importante quando falamos de expor um endpoint, precisamos saber quando há falhas, alto volume de acesso, gargalos, etc… Não devemos necessariamente ter que nos restringir a ter métricas de acesso, podemos ir um pouco mais além e ter logs de auditoria também, guardar os payloads recebidos por um curto período pode ajudar bastante em um eventual debug, facilitando muito o entendimento do processamento que não gerou o resultado esperado. Os seguintes pontos ajudam consideravelmente:
Métricas de requests
Quantidade de requests: Esse dado nos ajuda a entender os picos de utilização. Ex: total de requisições por minuto, etc..
Código de retorno: Já esse nos ajuda a entender quando há problemas no servidor ou no cliente. Então é interessante ter os códigos de retorno http registrados. Ex: 5xx, 4xx, etc…
Tempo total dos requests: Aqui podemos ter uma visão de gargalos eventuais, e quem está sendo afetado. Ex: média do tempo de resposta, máximo e mínimo também.
Logs de auditoria
Identificação do client: Devemos ter como relacionar um determinado registro de auditoria a um client.
Payload utilizado na mensagem: Para um possível debug, é importante ter o payload registrado por um curto período.
Finalizando
Disponibilizar um endpoint de Webhook na sua aplicação vai muito além de criar uma nova rota de POST no nosso servidor. Precisamos garantir uma mentalidade direcionada para a segurança e para o processamento assíncrono, sempre com a visão de performance e disponibilidade. Quando lidamos com a idéia de que toda requisição é potencialmente não confiável, e garantimos que haverá um fluxo de processamento assíncrono, de fato estamos construindo sistemas muito mais estáveis e de alta qualidade.
Você gostou do conteúdo? Já teve alguma experiência com Webhooks? Comente aqui abaixo, será um prazer responder.


