API e Desenvolvedores
Tratamento de erros
5 min de leitura
A API do Radar DOU utiliza codigos de status HTTP padrao e retorna mensagens de erro detalhadas em formato JSON. Este guia explica como interpretar e tratar os diferentes tipos de erros.
Estrutura de Resposta de Erro
Quando ocorre um erro, a API retorna uma resposta JSON com a seguinte estrutura:
{
"sucesso": false,
"erro": {
"codigo": "CODIGO_DO_ERRO",
"mensagem": "Descricao legivel do erro",
"detalhes": {
// Informacoes adicionais especificas do erro
},
"request_id": "req_abc123xyz",
"documentacao": "https://radardou.com.br/docs/erros#CODIGO_DO_ERRO"
}
}Codigos de Status HTTP
| Codigo | Status | Descricao | Acao |
|---|---|---|---|
| 200 | OK | Requisicao bem-sucedida | Processar resposta normalmente |
| 400 | Bad Request | Parametros invalidos | Corrigir parametros e reenviar |
| 401 | Unauthorized | Autenticacao falhou | Verificar API Key |
| 403 | Forbidden | Sem permissao | Verificar permissoes da API Key |
| 404 | Not Found | Recurso nao existe | Verificar ID ou endpoint |
| 422 | Unprocessable | Validacao falhou | Verificar formato dos dados |
| 429 | Too Many Requests | Rate limit excedido | Aguardar e tentar novamente |
| 500 | Internal Error | Erro no servidor | Tentar novamente ou contatar suporte |
| 503 | Service Unavailable | Servico indisponivel | Aguardar e tentar novamente |
Codigos de Erro Especificos
Erros de Autenticacao (401)
| Codigo | Descricao | Solucao |
|---|---|---|
MISSING_API_KEY | Header X-API-Key ausente | Adicionar header X-API-Key |
INVALID_API_KEY | API Key invalida ou malformada | Verificar formato da chave |
EXPIRED_API_KEY | API Key expirada | Gerar nova chave no painel |
REVOKED_API_KEY | API Key foi revogada | Usar outra chave ativa |
Erros de Validacao (400/422)
| Codigo | Descricao | Exemplo |
|---|---|---|
MISSING_PARAMETER | Parametro obrigatorio ausente | Faltou "termo" na busca |
INVALID_PARAMETER | Valor de parametro invalido | limite=500 (max 100) |
INVALID_DATE_FORMAT | Formato de data invalido | Use YYYY-MM-DD |
INVALID_DATE_RANGE | Intervalo de data invalido | data_inicio > data_fim |
INVALID_SECTION | Secao invalida | Use 1, 2, 3 ou extra |
Erros de Rate Limit (429)
{
"sucesso": false,
"erro": {
"codigo": "RATE_LIMIT_EXCEEDED",
"mensagem": "Limite de 60 requisicoes por minuto excedido",
"detalhes": {
"limite": 60,
"janela": "minuto",
"retry_after": 45
}
}
}
// Outros codigos de rate limit:
// DAILY_LIMIT_EXCEEDED - Limite diario atingido
// MONTHLY_QUOTA_EXCEEDED - Quota mensal esgotadaTratamento de Erros em Python
import requests
from typing import Optional, Dict, Any
class RadarDOUError(Exception):
"""Erro base da API Radar DOU."""
def __init__(self, status_code: int, codigo: str, mensagem: str,
request_id: str = None, detalhes: dict = None):
self.status_code = status_code
self.codigo = codigo
self.mensagem = mensagem
self.request_id = request_id
self.detalhes = detalhes or {}
super().__init__(f"[{codigo}] {mensagem}")
class AuthenticationError(RadarDOUError):
"""Erro de autenticacao (401)."""
pass
class ValidationError(RadarDOUError):
"""Erro de validacao (400/422)."""
pass
class NotFoundError(RadarDOUError):
"""Recurso nao encontrado (404)."""
pass
class RateLimitError(RadarDOUError):
"""Rate limit excedido (429)."""
@property
def retry_after(self) -> int:
return self.detalhes.get('retry_after', 60)
class ServerError(RadarDOUError):
"""Erro interno do servidor (5xx)."""
pass
def parse_error_response(response: requests.Response) -> RadarDOUError:
"""Converte resposta de erro em excecao apropriada."""
try:
data = response.json()
erro = data.get('erro', {})
except:
erro = {'codigo': 'UNKNOWN', 'mensagem': response.text}
codigo = erro.get('codigo', 'UNKNOWN')
mensagem = erro.get('mensagem', 'Erro desconhecido')
request_id = erro.get('request_id')
detalhes = erro.get('detalhes', {})
error_classes = {
401: AuthenticationError,
400: ValidationError,
422: ValidationError,
404: NotFoundError,
429: RateLimitError,
}
error_class = error_classes.get(
response.status_code,
ServerError if response.status_code >= 500 else RadarDOUError
)
return error_class(
response.status_code, codigo, mensagem, request_id, detalhes
)
def api_request(endpoint: str, params: dict = None) -> Dict[str, Any]:
"""Faz requisicao com tratamento de erros."""
response = requests.get(
f'https://radardou.com.br/api/v1{endpoint}',
headers={'X-API-Key': API_KEY},
params=params
)
if not response.ok:
raise parse_error_response(response)
return response.json()
# Uso com tratamento especifico
try:
resultado = api_request('/buscar', {'termo': 'licitacao'})
print(resultado)
except AuthenticationError as e:
print(f"Erro de autenticacao: {e.mensagem}")
print("Verifique sua API Key")
except ValidationError as e:
print(f"Erro de validacao: {e.mensagem}")
print(f"Detalhes: {e.detalhes}")
except RateLimitError as e:
print(f"Rate limit excedido. Aguarde {e.retry_after} segundos")
except NotFoundError as e:
print(f"Recurso nao encontrado: {e.mensagem}")
except ServerError as e:
print(f"Erro no servidor: {e.mensagem}")
print(f"Request ID para suporte: {e.request_id}")
except RadarDOUError as e:
print(f"Erro da API: {e}")Tratamento de Erros em JavaScript
class RadarDOUError extends Error {
constructor(statusCode, codigo, mensagem, requestId, detalhes = {}) {
super(`[${codigo}] ${mensagem}`);
this.name = 'RadarDOUError';
this.statusCode = statusCode;
this.codigo = codigo;
this.mensagem = mensagem;
this.requestId = requestId;
this.detalhes = detalhes;
}
}
class AuthenticationError extends RadarDOUError {
constructor(...args) {
super(...args);
this.name = 'AuthenticationError';
}
}
class RateLimitError extends RadarDOUError {
constructor(...args) {
super(...args);
this.name = 'RateLimitError';
}
get retryAfter() {
return this.detalhes.retry_after || 60;
}
}
async function apiRequest(endpoint, params = {}) {
const url = new URL(`https://radardou.com.br/api/v1${endpoint}`);
Object.entries(params).forEach(([key, value]) =>
url.searchParams.append(key, value)
);
const response = await fetch(url, {
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
const data = await response.json().catch(() => ({}));
const erro = data.erro || {};
const ErrorClass = {
401: AuthenticationError,
429: RateLimitError,
}[response.status] || RadarDOUError;
throw new ErrorClass(
response.status,
erro.codigo || 'UNKNOWN',
erro.mensagem || 'Erro desconhecido',
erro.request_id,
erro.detalhes
);
}
return response.json();
}
// Uso com async/await e try/catch
async function buscarPublicacoes(termo) {
try {
const resultado = await apiRequest('/buscar', { termo });
return resultado;
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Verifique sua API Key');
// Redirecionar para pagina de login/config
} else if (error instanceof RateLimitError) {
console.log(`Aguardando ${error.retryAfter}s...`);
await new Promise(r => setTimeout(r, error.retryAfter * 1000));
return buscarPublicacoes(termo); // Retry
} else if (error instanceof RadarDOUError) {
console.error(`Erro da API: ${error.mensagem}`);
console.error(`Request ID: ${error.requestId}`);
} else {
console.error('Erro inesperado:', error);
}
throw error;
}
}Implementando Retry com Backoff Exponencial
import time
import random
def request_with_retry(func, max_retries=3, base_delay=1):
"""
Executa funcao com retry e backoff exponencial.
Args:
func: Funcao a executar
max_retries: Numero maximo de tentativas
base_delay: Delay base em segundos
"""
last_error = None
for attempt in range(max_retries):
try:
return func()
except RateLimitError as e:
# Usar retry_after da API
wait_time = e.retry_after
print(f"Rate limit. Aguardando {wait_time}s...")
time.sleep(wait_time)
last_error = e
except ServerError as e:
# Backoff exponencial com jitter
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
print(f"Erro no servidor. Tentativa {attempt + 1}/{max_retries}. "
f"Aguardando {delay:.1f}s...")
time.sleep(delay)
last_error = e
else:
raise
except (AuthenticationError, ValidationError, NotFoundError):
# Erros que nao devem ser retentados
raise
raise last_error
# Uso
resultado = request_with_retry(
lambda: api_request('/buscar', {'termo': 'licitacao'}),
max_retries=5
)Logging de Erros para Debug
import logging
import json
# Configurar logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('radar_dou')
def log_api_error(error: RadarDOUError, context: dict = None):
"""Registra erro da API com contexto."""
error_info = {
'status_code': error.status_code,
'codigo': error.codigo,
'mensagem': error.mensagem,
'request_id': error.request_id,
'detalhes': error.detalhes,
'context': context or {}
}
if error.status_code >= 500:
logger.error(f"Erro do servidor: {json.dumps(error_info)}")
elif error.status_code == 429:
logger.warning(f"Rate limit excedido: {json.dumps(error_info)}")
else:
logger.info(f"Erro da API: {json.dumps(error_info)}")
# Uso
try:
resultado = api_request('/buscar', {'termo': 'licitacao'})
except RadarDOUError as e:
log_api_error(e, {'endpoint': '/buscar', 'termo': 'licitacao'})
raiseBoas Praticas de Tratamento de Erros
Recomendacoes
- Sempre verifique o status code antes de processar a resposta
- Implemente retry apenas para erros recuperaveis (429, 5xx)
- Use backoff exponencial para evitar sobrecarregar a API
- Registre o request_id para facilitar o suporte
- Trate cada tipo de erro de forma especifica
- Forneca mensagens claras ao usuario final
Obtendo Suporte
Se voce encontrar erros persistentes, entre em contato com nosso suporte incluindo:
- Request ID: Disponivel no campo
request_idda resposta de erro - Timestamp: Horario aproximado em que o erro ocorreu
- Endpoint: Qual endpoint estava sendo acessado
- Parametros: Quais parametros foram enviados (sem dados sensiveis)
Precisa de ajuda? Use nosso assistente virtual para tirar duvidas sobre erros especificos ou entre em contato com o suporte tecnico atraves do painel.
Ainda tem dúvidas?
Converse com nosso assistente virtual especializado para obter ajuda personalizada sobre qualquer funcionalidade.
