Radar DOU
Voltar para API e Desenvolvedores
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

CodigoStatusDescricaoAcao
200OKRequisicao bem-sucedidaProcessar resposta normalmente
400Bad RequestParametros invalidosCorrigir parametros e reenviar
401UnauthorizedAutenticacao falhouVerificar API Key
403ForbiddenSem permissaoVerificar permissoes da API Key
404Not FoundRecurso nao existeVerificar ID ou endpoint
422UnprocessableValidacao falhouVerificar formato dos dados
429Too Many RequestsRate limit excedidoAguardar e tentar novamente
500Internal ErrorErro no servidorTentar novamente ou contatar suporte
503Service UnavailableServico indisponivelAguardar e tentar novamente

Codigos de Erro Especificos

Erros de Autenticacao (401)

CodigoDescricaoSolucao
MISSING_API_KEYHeader X-API-Key ausenteAdicionar header X-API-Key
INVALID_API_KEYAPI Key invalida ou malformadaVerificar formato da chave
EXPIRED_API_KEYAPI Key expiradaGerar nova chave no painel
REVOKED_API_KEYAPI Key foi revogadaUsar outra chave ativa

Erros de Validacao (400/422)

CodigoDescricaoExemplo
MISSING_PARAMETERParametro obrigatorio ausenteFaltou "termo" na busca
INVALID_PARAMETERValor de parametro invalidolimite=500 (max 100)
INVALID_DATE_FORMATFormato de data invalidoUse YYYY-MM-DD
INVALID_DATE_RANGEIntervalo de data invalidodata_inicio > data_fim
INVALID_SECTIONSecao invalidaUse 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 esgotada

Tratamento 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'})
    raise

Boas 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_id da 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.

Abrir Assistente