Cache em API: guia passo a passo para implementar
A mudança de comportamento é clara: usuários e sistemas esperam respostas em milissegundos, e o custo de processar cada requisição do zero pesa no orçamento. Implementar cache em API deixou de ser otimização e virou requisito básico de arquitetura. Este guia mostra o caminho passo a passo, com decisões práticas e erros comuns, para você aplicar sem comprometer a consistência dos dados.
Implementar cache em API envolve definir o que armazenar, por quanto tempo e onde. O caminho básico inclui escolher a estratégia (em memória, HTTP ou banco), configurar os cabeçalhos de controle, definir a política de expiração e invalidar o cache quando os dados mudam. O objetivo é reduzir latência e custos sem servir dados obsoletos.
Pré-requisitos
Antes de começar, tenha clareza sobre o comportamento da sua API. Liste os endpoints mais acessados e identifique quais retornam dados que mudam com pouca frequência. Um endpoint de relatório diário é candidato natural; um endpoint de saldo em tempo real não é.
Você também precisa de acesso à configuração do servidor ou ao código da aplicação, dependendo da camada onde o cache será aplicado. Não há uma única resposta certa, e a decisão depende do seu cenário.
Passo 1: Mapeie os endpoints candidatos a cache
Comece analisando os logs de acesso. Identifique os endpoints com maior volume de requisições e avalie a frequência de atualização dos dados que eles retornam. Um bom candidato responde a duas perguntas: o dado muda raramente? A resposta é a mesma para a maioria dos usuários?
Um erro comum é tentar colocar cache em tudo. Endpoints que dependem do usuário autenticado, como perfil ou saldo, exigem cuidado extra e, muitas vezes, não se beneficiam do cache simples. Para esses casos, a estratégia é diferente e será tratada adiante.
Passo 2: Escolha a camada de cache
Existem três camadas principais, e você pode combinar mais de uma.
Cache em memória (in-process): armazena os dados dentro do processo da aplicação. É rápido e simples de implementar, mas o cache se perde quando o servidor reinicia. Útil para dados que podem ser recarregados sem grande custo.
Cache HTTP (CDN ou proxy reverso): usa cabeçalhos como Cache-Control para que intermediários, como um CDN, armazenem a resposta. É eficaz para conteúdo público e reduz a carga no servidor de origem. A configuração é feita no servidor ou na aplicação.
Cache em banco (Redis, Memcached): uma camada externa compartilhada entre várias instâncias da aplicação. Indicado para dados que precisam ser acessados por múltiplos servidores ou que devem sobreviver a reinícios.
A escolha depende do seu contexto. Uma API pequena pode começar com cache em memória. Uma API distribuída precisa de uma solução externa.
Passo 3: Defina a política de expiração (TTL)
O TTL (Time To Live) define por quanto tempo a resposta fica armazenada antes de ser considerada obsoleta. Não existe um valor universal. Um dado de configuração pode ter TTL de horas; um preço de ação, de segundos.
Uma abordagem segura é começar com um TTL conservador e aumentar gradualmente, observando o impacto na consistência. Erro comum: definir TTL longo demais para dados que mudam com frequência, o que gera respostas desatualizadas e reclamações de usuários.
Passo 4: Configure os cabeçalhos HTTP
Para cache em camada HTTP, os cabeçalhos são essenciais. O Cache-Control define a diretiva: public para respostas que podem ser armazenadas por qualquer intermediário, private para respostas específicas do usuário, e max-age para o tempo de validade em segundos.
Exemplo prático: Cache-Control: public, max-age=3600 indica que a resposta pode ser armazenada publicamente por uma hora. O cabeçalho ETag permite validação: o cliente envia o ETag na próxima requisição e o servidor responde com 304 (Not Modified) se o conteúdo não mudou, economizando banda.
Um erro comum é ignorar o cabeçalho Vary. Se a resposta varia conforme o idioma ou o tipo de autenticação, o Vary precisa refletir isso, ou usuários podem receber conteúdo errado.
Passo 5: Implemente a lógica de cache no código
Se a opção for cache em memória ou em banco, a implementação segue um padrão simples: verifique se a chave existe no cache; se existir, retorne o valor; se não, busque na fonte original, armazene no cache e retorne.
A chave deve ser única e estável. Uma combinação de endpoint e parâmetros de consulta costuma funcionar, mas cuidado com dados específicos do usuário. Nesse caso, inclua o identificador do usuário na chave ou use a diretiva private.
Erro comum: armazenar objetos complexos sem serialização adequada. Certifique-se de que o que é gravado no cache pode ser lido corretamente, especialmente em sistemas com vários tipos de dados.
Passo 6: Invalide o cache quando os dados mudarem
Cache não é só escrever; é também invalidar. Quando um dado é atualizado, o cache correspondente precisa ser removido ou atualizado. Duas abordagens comuns: invalidar a chave específica após uma alteração, ou usar uma versão global que muda a cada atualização relevante.
Um erro comum é invalidar apenas o endpoint que recebeu a atualização, esquecendo endpoints que retornam o mesmo dado de forma agregada. Mapeie todas as respostas que dependem daquele dado e invalide todas.
Passo 7: Monitore e ajuste
Após implementar, monitore a taxa de acerto do cache (hit ratio), a latência média e a quantidade de dados obsoletos servidos. Essas métricas indicam se a estratégia está funcionando ou se o TTL precisa de ajuste.
Um erro comum é configurar o cache e nunca mais revisar. O comportamento dos dados muda, o tráfego muda, e o que era eficiente ontem pode ser problemático hoje. Revise a política periodicamente.
Checklist final do que foi implementado
- Endpoints candidatos identificados com base em volume e frequência de atualização.
- Camada de cache escolhida (memória, HTTP ou banco) conforme o cenário.
- TTL definido para cada tipo de dado, com valor inicial conservador.
- Cabeçalhos HTTP configurados (
Cache-Control,ETag,Varyquando necessário). - Lógica de leitura e escrita no código implementada com chave estável.
- Invalidação de cache funcional para todas as respostas dependentes.
- Métricas de acerto e latência em monitoramento contínuo.
Perguntas frequentes sobre cache em API
Qual a diferença entre cache privado e público?
Cache privado é armazenado no navegador do usuário e não é compartilhado. Cache público pode ser armazenado por intermediários, como CDNs, e é compartilhado entre vários usuários. A escolha depende da natureza dos dados: dados pessoais exigem private; dados públicos, public.
Cache em memória é suficiente para uma API pequena?
Para uma API com poucas instâncias e dados que podem ser recarregados, o cache em memória pode ser suficiente. Ele é simples e rápido. Porém, se a aplicação for distribuída, o cache em memória gera inconsistência entre instâncias, e uma solução externa como Redis é mais adequada.
Como evitar servir dados obsoletos?
A principal defesa é um TTL adequado e uma estratégia de invalidação. Se o dado muda com frequência, reduza o TTL. Se a mudança é previsível, invalide a chave no momento da atualização. Monitore a idade dos dados servidos para detectar problemas.
O que é ETag e como usar?
ETag é um identificador de versão do recurso. O servidor envia o ETag junto com a resposta. Na próxima requisição, o cliente envia o ETag no cabeçalho If-None-Match. Se o recurso não mudou, o servidor responde com 304, sem reenviar o corpo. Isso economiza banda.
Cache em API afeta a segurança?
Pode afetar se dados sensíveis forem armazenados em cache público. Para evitar vazamentos, use Cache-Control: private para dados de usuário e evite armazenar tokens ou informações pessoais em camadas compartilhadas. A invalidação adequada também reduz o risco de exposição.
Qual a melhor estratégia para dados que variam por usuário?
Para dados personalizados, o cache público não é adequado. Use cache privado no navegador ou cache em banco com chave que inclua o identificador do usuário. Alternativamente, evite cache e processe a resposta a cada requisição, se o volume justificar.