Formato de erros, códigos e estratégias de retry da Storefront API.
A API retorna erros no formato padrão GraphQL. Cada erro inclui uma message e um code nas extensions:
| Código | HTTP | Descrição |
|---|---|---|
| UNAUTHENTICATED | 200 | Operação requer autenticação. O usuário não está logado ou a sessão expirou. |
| BAD_REQUEST | 200 | Query malformada, sintaxe inválida ou campos obrigatórios ausentes. |
| UNHANDLED_ERROR | 200 | Erro interno do servidor. Contate o suporte se persistir. |
| STOREFRONT_RATE_LIMIT_EXCEEDED | 429 | Limite de tokens da API excedido. Aguarde e tente novamente. |
| QUERY_COMPLEXITY_EXCEEDED | 429 | Query muito complexa (muitos campos). Simplifique ou divida em múltiplas queries. |
| RATE_LIMIT_EXCEEDED | 429 | Limite de rate para mutation específica excedido. |
Quando o rate limit é excedido, a resposta inclui headers para ajudar no retry:
| Header | Descrição |
|---|---|
| X-RateLimit-Limit | Limite total de tokens na janela. |
| X-RateLimit-Remaining | Tokens restantes na janela atual. |
| X-RateLimit-Reset | Timestamp ISO 8601 de quando a janela reseta. |
| Retry-After | Segundos até que novas requests sejam aceitas. |
Veja o Guia de Rate Limits para detalhes sobre custos de tokens e limites.
Erros de validação de input retornam detalhes sobre os campos inválidos na mensagem. Verifique os campos obrigatórios documentados em cada mutation.
Para erros de rate limit (429), use exponential backoff:
Retry-AfterUNAUTHENTICATED não devem ser retried. Redirecione o usuário para a tela de login. Erros UNHANDLED_ERROR podem ser retried uma vez, mas se persistirem indicam um bug no servidor.
{
"data": null,
"errors": [{
"message": "Not authenticated",
"code": "UNAUTHENTICATED"
}]
} {
"errors": [{
"message": "Storefront API rate limit exceeded for read operations. Try again in 12 seconds.",
"extensions": {
"code": "STOREFRONT_RATE_LIMIT_EXCEEDED",
"operationType": "read",
"retryAfterSeconds": 12
}
}]
} {
"errors": [{
"message": "Query too complex (estimated 45 fields, limit 20).",
"extensions": {
"code": "QUERY_COMPLEXITY_EXCEEDED",
"complexity": 45,
"limit": 20
}
}]
} async function fetchWithRetry(query, variables, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch('/graphql', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
});
if (response.status !== 429) {
return response.json();
}
const retryAfter = response.headers.get('Retry-After');
const waitMs = retryAfter
? parseInt(retryAfter) * 1000
: Math.pow(2, attempt) * 1000;
await new Promise(r => setTimeout(r, waitMs));
}
throw new Error('Max retries exceeded');
}