(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como fazer cache de respostas de uma API em Python

João Barros 14 de July de 2026 4 min de leitura

Chamar repetidamente a mesma API é lento e gasta o teu limite de pedidos sem necessidade. Fazer cache de respostas de uma API em Python resolve o problema: a resposta fica guardada localmente e, no pedido seguinte, é lida do disco em milissegundos. Com a biblioteca requests-cache consegues isto sem alterar praticamente nada no código que já tens.

Pré-requisitos

  • Python 3.8 ou superior instalado.
  • Saber o básico da biblioteca requests (fazer um GET).
  • Uma API REST pública para testar — usamos https://api.github.com como exemplo.

Passo 1: Instalar o requests-cache

A instalação é feita com pip. O requests-cache é um complemento do requests, por isso instalamos os dois.

pip install requests requests-cache

Passo 2: Criar uma CachedSession

Em vez de usares requests.get() diretamente, crias uma CachedSession. Ela funciona exatamente como uma sessão normal, mas guarda cada resposta num ficheiro SQLite. O parâmetro expire_after define durante quantos segundos a cópia é considerada válida.

from requests_cache import CachedSession

session = CachedSession(
    cache_name="api_cache",   # cria o ficheiro api_cache.sqlite
    backend="sqlite",
    expire_after=3600,        # a resposta é válida durante 1 hora
)

resposta = session.get("https://api.github.com/repos/psf/requests")
print(resposta.status_code, resposta.from_cache)

Na primeira execução vês 200 False: a resposta veio da rede. Na segunda, vês 200 True — veio do cache.

Passo 3: Medir o ganho de tempo

Vale a pena confirmar o efeito com um exemplo simples. A diferença entre uma chamada de rede e uma leitura do cache costuma ser de centenas de milissegundos para poucos milissegundos.

import time

for i in range(2):
    inicio = time.perf_counter()
    r = session.get("https://api.github.com/repos/psf/requests")
    duracao = (time.perf_counter() - inicio) * 1000
    print(f"chamada {i+1}: from_cache={r.from_cache} ({duracao:.0f} ms)")

Passo 4: Controlar o que é guardado

Guardar tudo é raramente o que queres. Um erro comum é ficar com uma resposta de erro presa no cache. Restringe o cache a respostas 200 e a métodos GET, e define tempos diferentes por tipo de endpoint.

session = CachedSession(
    cache_name="api_cache",
    expire_after=300,              # 5 minutos por omissão
    allowable_codes=[200],         # só guarda respostas com sucesso
    allowable_methods=["GET"],     # nunca guarda POST/PUT
    stale_if_error=True,           # se a API falhar, usa a cópia antiga
    urls_expire_after={
        "*/rate_limit": 0,     # este endpoint nunca é guardado
        "*/repos/*": 86400 # dados de repositórios: 1 dia
    },
)

A opção stale_if_error=True é a que mais te vai salvar: se a API estiver em baixo ou devolver erro 429, o teu script continua a funcionar com a última resposta boa em vez de rebentar.

Passo 5: Forçar atualização e limpar o cache

Às vezes precisas mesmo do valor mais recente, ou queres arrumar o ficheiro. Podes ignorar o cache num único pedido com refresh=True e apagar entradas com os métodos do objeto session.cache.

from requests_cache import CachedSession

session = CachedSession("api_cache", expire_after=3600)

# ignora o cache apenas neste pedido e atualiza a cópia guardada
r = session.get("https://api.github.com/repos/psf/requests", refresh=True)

# remove só as entradas já expiradas
session.cache.delete(expired=True)

# apaga tudo
session.cache.clear()

Verificar o resultado

Três sinais confirmam que ficou bem feito:

  1. Existe um ficheiro api_cache.sqlite na pasta do teu script.
  2. A segunda chamada ao mesmo URL devolve r.from_cache == True.
  3. O tempo da segunda chamada é uma ordem de grandeza menor.
print(len(session.cache.responses))   # nº de respostas guardadas
print(list(session.cache.urls())[:5]) # URLs em cache

Se from_cache continuar a dar False, confirma que estás a usar a session (e não requests.get) e que o expire_after não é 0.

Conclusão

Com meia dúzia de linhas passaste a poupar chamadas, a fugir a erros 429 e a tornar o teu script muito mais rápido em desenvolvimento. O passo seguinte natural é levar este cache para produção: troca o backend SQLite por Redis (backend="redis") para o partilhares entre vários processos, e afina o expire_after por endpoint. Uma pergunta para fechar: quais dos endpoints que usas mudam mesmo de minuto a minuto — e quais é que podias guardar durante um dia inteiro sem ninguém dar por isso?