Cache e requisições condicionais
Toda resposta GET da API do Bordio carrega um ETag. Ao enviá-lo de volta na sua próxima requisição, você pode perguntar “isso mudou?” e receber um pequeno 304 Not Modified em vez do corpo completo quando nada mudou.
Por que existe
Seção intitulada “Por que existe”A maior parte dos dados que você lê — listas de tarefas, definições, campos personalizados — muda com muito menos frequência do que você faz sondagem. Sem cache, todo GET baixa novamente um corpo idêntico. As requisições condicionais permitem que você:
- Economize largura de banda — um recurso inalterado retorna como um
304vazio em vez do payload completo. - Revalide de forma econômica — uma única ida e volta confirma que sua cópia em cache ainda está atual.
- Simplifique a lógica de cache — o servidor informa quando atualizar; você nunca precisa adivinhar.
Como o servidor se comporta
Seção intitulada “Como o servidor se comporta”Em todo GET, a API define dois cabeçalhos:
ETag: "e3b0c44298fc1c149afbf4c8996fb924"Cache-Control: private, no-cache- O
ETagé um validador forte calculado sobre o corpo exato da resposta — se o corpo mudar de qualquer forma, oETagmuda. Cache-Control: private, no-cachesignifica: você pode armazenar a resposta, mas deve revalidá-la com o servidor antes de reutilizá-la (não a sirva às cegas), e ela é privada desta chave — nunca a armazene em um cache compartilhado/CDN.
Isso se aplica a todos os endpoints GET — tarefas, subtarefas, eventos, projetos, membros e todos os recursos de definições (status de tarefas, tipos, campos personalizados, tags…).
Como usar
Seção intitulada “Como usar”- Em um
GET, armazene o corpo da resposta junto com seuETag. - No seu próximo
GETdo mesmo recurso, envie o valor armazenado em um cabeçalhoIf-None-Match. - O servidor o compara com o
ETagatual:- Correspondência →
304 Not Modifiedcom um corpo vazio. Reutilize sua cópia em cache. - Sem correspondência →
200 OKcom o novo corpo e um novoETag. Substitua sua cópia em cache e oETagarmazenado.
- Correspondência →
# Primeira requisição — observe o ETagcurl -i "https://api.bordio.com/public/v1/custom_fields?project_id=proj_6594a1b2c3d4e5f6a7b8c9d0" \ -H "Authorization: Bearer brd_sk_live_..."# → 200 OK# ETag: "e3b0c44298fc1c149afbf4c8996fb924"
# Mais tarde — revalide com o ETag armazenadocurl -i "https://api.bordio.com/public/v1/custom_fields?project_id=proj_6594a1b2c3d4e5f6a7b8c9d0" \ -H "Authorization: Bearer brd_sk_live_..." \ -H 'If-None-Match: "e3b0c44298fc1c149afbf4c8996fb924"'# → 304 Not Modified (sem corpo — sua cópia em cache ainda está atual)Um cache de cliente mínimo:
const cache = new Map(); // url -> { etag, body }
async function getCached(url, apiKey) { const prev = cache.get(url); const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}`, ...(prev ? { 'If-None-Match': prev.etag } : {}), }, });
if (res.status === 304) return prev.body; // inalterado — reutiliza o cache
const body = await res.json(); cache.set(url, { etag: res.headers.get('ETag'), body }); return body;}Comparação fraca
Seção intitulada “Comparação fraca”If-None-Match é comparado usando a função de comparação fraca (RFC 7232 §3.2), então a revalidação é tolerante quanto ao prefixo de validador fraco:
- Um prefixo
W/em qualquer lado é ignorado —W/"abc"e"abc"são tratados como a mesma tag. - Você pode enviar uma lista separada por vírgulas de tags; uma correspondência em qualquer uma satisfaz a condição:
If-None-Match: "abc", W/"def". - Você pode enviar
*, que corresponde a qualquer representação atual.
Normalmente você apenas devolve a string exata do ETag que recebeu — a comparação fraca simplesmente significa que uma tag com prefixo W/ do seu cliente HTTP ainda corresponde.
Coisas a ter em mente
Seção intitulada “Coisas a ter em mente”- Trate o
ETagcomo opaco. É um hash — não o analise, compare apenas por igualdade, armazene-o literalmente. - Um
304ainda conta como uma requisição no seu limite de taxa e uso. As requisições condicionais economizam largura de banda, não o seu orçamento de requisições — então mantenha um intervalo de sondagem sensato. - O
ETagé por representação. Parâmetros de consulta diferentes (por exemplo, umproject_iddiferente, cursor de página ou filtro) produzem corpos diferentes e, portanto,ETags diferentes. Faça cache deles por URL completa. - As requisições condicionais se aplicam apenas a leituras (
GET). As escritas (POST/PATCH/DELETE) nunca são condicionais aqui — para novas tentativas seguras de escritas, use chaves de idempotência em vez disso.