Tratamento de Erros
Aprenda a lidar com erros de forma robusta e implementar retries adequados.
Formato de erro
Todas as APIs Axon retornam erros em um formato consistente:
error-response.jsonjson
{
"error": {
"code": "INVALID_REQUEST",
"message": "The card number is invalid",
"details": {
"field": "card.number",
"reason": "failed_luhn_check"
},
"request_id": "req_abc123def456",
"doc_url": "https://docs.axon.com/errors/INVALID_REQUEST"
}
}Codigos HTTP
| Codigo | Descricao | Acao |
|---|---|---|
| 200 | Sucesso | Processar resposta |
| 400 | Request invalido | Corrigir parametros |
| 401 | Nao autenticado | Verificar API key |
| 403 | Sem permissao | Verificar permissoes |
| 404 | Nao encontrado | Verificar ID/path |
| 409 | Conflito | Verificar estado |
| 429 | Rate limit | Retry com backoff |
| 500 | Erro interno | Retry com backoff |
| 503 | Servico indisponivel | Retry com backoff |
Implementando retries
retry-handler.jsjavascript
class AxonClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.axon.com';
this.maxRetries = 3;
}
async request(method, path, data, options = {}) {
let lastError;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...(options.idempotencyKey && {
'Idempotency-Key': options.idempotencyKey,
}),
},
body: data ? JSON.stringify(data) : undefined,
});
// Sucesso - retorna resposta
if (response.ok) {
return response.json();
}
const error = await response.json();
// Erros que nao devem ser retentados
if ([400, 401, 403, 404, 409].includes(response.status)) {
throw new AxonError(error.error, response.status);
}
// Rate limit - usar Retry-After
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '1');
await this.sleep(retryAfter * 1000);
continue;
}
// Erros 5xx - retry com backoff
lastError = new AxonError(error.error, response.status);
} catch (error) {
if (error instanceof AxonError) throw error;
lastError = error;
}
// Calcular delay com exponential backoff + jitter
if (attempt < this.maxRetries) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
const jitter = Math.random() * 1000;
await this.sleep(delay + jitter);
}
}
throw lastError;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
class AxonError extends Error {
constructor(error, status) {
super(error.message);
this.code = error.code;
this.status = status;
this.details = error.details;
this.requestId = error.request_id;
}
}Quando fazer retry
Faca retry apenas para erros 429, 500, 502, 503 e 504. Erros 4xx (exceto 429) indicam problemas com o request e nao devem ser retentados.
Tratamento por tipo de erro
error-handling.jsjavascript
async function processPayment(tokenId, amount) {
try {
const payment = await axon.request('POST', '/v1/payments', {
token_id: tokenId,
amount,
}, {
idempotencyKey: generateIdempotencyKey(),
});
return { success: true, payment };
} catch (error) {
if (error instanceof AxonError) {
switch (error.code) {
case 'INVALID_TOKEN':
// Token invalido ou expirado
return { success: false, action: 'request_new_card' };
case 'INSUFFICIENT_FUNDS':
// Saldo insuficiente
return { success: false, action: 'notify_user' };
case 'CARD_DECLINED':
// Cartao recusado pelo banco
return { success: false, action: 'try_another_card' };
case 'RATE_LIMIT_EXCEEDED':
// Rate limit - ja foi tratado com retry
return { success: false, action: 'try_later' };
case 'DUPLICATE_REQUEST':
// Request duplicado (idempotency)
// Buscar resultado anterior
return await getExistingPayment(error.details.existing_id);
default:
// Erro desconhecido - logar e notificar
console.error('Unexpected error:', error);
return { success: false, action: 'contact_support' };
}
}
// Erro de rede ou outro
console.error('Network error:', error);
return { success: false, action: 'retry_later' };
}
}Logging e monitoramento
logging.jsjavascript
function logApiError(error, context) {
const logEntry = {
timestamp: new Date().toISOString(),
level: 'error',
service: 'axon-integration',
error: {
code: error.code,
message: error.message,
status: error.status,
requestId: error.requestId,
},
context: {
endpoint: context.endpoint,
method: context.method,
customerId: context.customerId,
},
};
// Enviar para sistema de logs
console.error(JSON.stringify(logEntry));
// Alertar para erros criticos
if (error.status >= 500) {
alertOncall(logEntry);
}
}
// Metricas para monitoramento
function recordMetric(endpoint, status, duration) {
metrics.histogram('axon_api_request_duration', duration, {
endpoint,
status: String(status),
});
if (status >= 400) {
metrics.increment('axon_api_errors', {
endpoint,
status: String(status),
});
}
}