Códigos de Status HTTP

Códigos de Sucesso

  • 200 OK: Requisição processada com sucesso
  • 201 Created: Recurso criado com sucesso
  • 202 Accepted: Requisição aceita para processamento assíncrono

Códigos de Erro do Cliente

  • 400 Bad Request: Parâmetros inválidos ou malformados
  • 401 Unauthorized: API Key ausente ou inválida
  • 403 Forbidden: Acesso negado ao recurso
  • 404 Not Found: Recurso não encontrado
  • 409 Conflict: Conflito com estado atual do recurso
  • 422 Unprocessable Entity: Dados válidos mas não processáveis
  • 429 Too Many Requests: Rate limit excedido

Códigos de Erro do Servidor

  • 500 Internal Server Error: Erro interno do servidor
  • 502 Bad Gateway: Erro de gateway
  • 503 Service Unavailable: Serviço temporariamente indisponível
  • 504 Gateway Timeout: Timeout de gateway

Estrutura de Resposta de Erro

Todas as respostas de erro seguem um formato consistente:
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Parâmetros de entrada inválidos",
    "details": {
      "field": "cpf",
      "reason": "Formato de CPF inválido",
      "provided": "123.456.789-00"
    },
    "request_id": "req_1234567890abcdef",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Campos da Resposta de Erro

  • code: Código único do erro para identificação programática
  • message: Mensagem descritiva em português
  • details: Informações adicionais específicas do erro
  • request_id: ID único da requisição para rastreamento
  • timestamp: Timestamp do erro em formato ISO 8601

Códigos de Erro Específicos

Autenticação e Autorização

CódigoDescriçãoStatus HTTP
INVALID_API_KEYAPI Key inválida ou expirada401
MISSING_API_KEYAPI Key não fornecida401
INSUFFICIENT_PERMISSIONSPermissões insuficientes403
ACCOUNT_SUSPENDEDConta suspensa403

Validação de Dados

CódigoDescriçãoStatus HTTP
VALIDATION_ERRORErro de validação geral400
INVALID_CPFCPF em formato inválido400
INVALID_CNPJCNPJ em formato inválido400
INVALID_OABNúmero OAB inválido400
INVALID_CNJNúmero CNJ inválido400
MISSING_REQUIRED_FIELDCampo obrigatório ausente400
INVALID_DATE_FORMATFormato de data inválido400

Rate Limiting

CódigoDescriçãoStatus HTTP
RATE_LIMIT_EXCEEDEDLimite de requisições excedido429
QUOTA_EXCEEDEDCota mensal excedida429
CONCURRENT_LIMIT_EXCEEDEDLimite de requisições simultâneas excedido429

Recursos e Processamento

CódigoDescriçãoStatus HTTP
RESOURCE_NOT_FOUNDRecurso não encontrado404
REQUEST_NOT_FOUNDRequisição não encontrada404
TRACKING_NOT_FOUNDTracking não encontrado404
PROCESSING_ERRORErro durante processamento422
TRIBUNAL_UNAVAILABLETribunal temporariamente indisponível503
TIMEOUT_ERRORTimeout na consulta ao tribunal504

Credenciais e Vault

CódigoDescriçãoStatus HTTP
INVALID_CREDENTIALSCredenciais inválidas400
CREDENTIALS_NOT_FOUNDCredenciais não encontradas404
ENCRYPTION_ERRORErro na criptografia500
VAULT_UNAVAILABLEVault temporariamente indisponível503

Estratégias de Tratamento

1. Retry com Backoff Exponencial

import time
import random
import requests
from typing import Optional

def make_request_with_retry(
    url: str,
    headers: dict,
    max_retries: int = 3,
    base_delay: float = 1.0
) -> Optional[requests.Response]:
    """
    Faz requisição com retry e backoff exponencial
    """
    for attempt in range(max_retries + 1):
        try:
            response = requests.get(url, headers=headers, timeout=30)
            
            # Sucesso
            if response.status_code < 400:
                return response
            
            # Não fazer retry para erros do cliente (4xx)
            if 400 <= response.status_code < 500:
                if response.status_code == 429:  # Rate limit
                    # Aguardar tempo especificado no header
                    retry_after = response.headers.get('Retry-After')
                    if retry_after:
                        time.sleep(int(retry_after))
                        continue
                else:
                    # Outros erros 4xx não devem ter retry
                    return response
            
            # Retry para erros 5xx
            if attempt < max_retries:
                delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
                print(f"Tentativa {attempt + 1} falhou. Aguardando {delay:.2f}s...")
                time.sleep(delay)
            else:
                return response
                
        except requests.exceptions.RequestException as e:
            if attempt < max_retries:
                delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
                print(f"Erro de conexão. Tentativa {attempt + 1}. Aguardando {delay:.2f}s...")
                time.sleep(delay)
            else:
                raise e
    
    return None

# Uso
response = make_request_with_retry(
    'https://requests.prod.judit.io/requests',
    headers={'api-key': os.getenv('JUDIT_API_KEY')}
)

2. Tratamento Específico por Tipo de Erro

def handle_api_error(response: requests.Response) -> None:
    """
    Trata erros específicos da API
    """
    if response.status_code == 200:
        return
    
    try:
        error_data = response.json().get('error', {})
        error_code = error_data.get('code', 'UNKNOWN_ERROR')
        error_message = error_data.get('message', 'Erro desconhecido')
        request_id = error_data.get('request_id', 'N/A')
        
        print(f"Erro {response.status_code}: {error_message}")
        print(f"Código: {error_code}")
        print(f"Request ID: {request_id}")
        
        # Tratamento específico por código
        if error_code == 'INVALID_API_KEY':
            print("⚠️ Verifique sua API Key")
            
        elif error_code == 'RATE_LIMIT_EXCEEDED':
            retry_after = response.headers.get('Retry-After', '60')
            print(f"⏳ Rate limit excedido. Aguarde {retry_after}s")
            
        elif error_code == 'VALIDATION_ERROR':
            details = error_data.get('details', {})
            field = details.get('field', 'desconhecido')
            reason = details.get('reason', 'erro de validação')
            print(f"❌ Campo '{field}': {reason}")
            
        elif error_code == 'TRIBUNAL_UNAVAILABLE':
            print("🏛️ Tribunal temporariamente indisponível")
            
        elif error_code == 'PROCESSING_ERROR':
            print("⚙️ Erro no processamento. Tente novamente")
            
        else:
            print(f"❓ Erro não tratado: {error_code}")
            
    except (ValueError, KeyError) as e:
        print(f"Erro ao processar resposta de erro: {e}")
        print(f"Status: {response.status_code}")
        print(f"Resposta: {response.text[:200]}...")

# Uso
response = requests.get(
    'https://requests.prod.judit.io/requests',
    headers={'api-key': os.getenv('JUDIT_API_KEY')}
)

handle_api_error(response)

3. Logging e Monitoramento

import logging
import json
from datetime import datetime

# Configurar logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('judit_api')

def log_api_error(response: requests.Response, context: dict = None) -> None:
    """
    Registra erros da API para monitoramento
    """
    try:
        error_data = response.json().get('error', {})
    except:
        error_data = {}
    
    log_entry = {
        'timestamp': datetime.utcnow().isoformat(),
        'status_code': response.status_code,
        'error_code': error_data.get('code', 'UNKNOWN'),
        'error_message': error_data.get('message', 'Erro desconhecido'),
        'request_id': error_data.get('request_id'),
        'url': response.url,
        'context': context or {}
    }
    
    if response.status_code >= 500:
        logger.error(f"Erro do servidor: {json.dumps(log_entry)}")
    elif response.status_code >= 400:
        logger.warning(f"Erro do cliente: {json.dumps(log_entry)}")
    else:
        logger.info(f"Requisição processada: {json.dumps(log_entry)}")

# Uso
response = requests.get(
    'https://requests.prod.judit.io/requests',
    headers={'api-key': os.getenv('JUDIT_API_KEY')}
)

log_api_error(response, context={'operation': 'list_requests'})

Exemplo de Implementação Completa

import os
import time
import random
import requests
import logging
from typing import Optional, Dict, Any

class JuditAPIClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_headers = {'api-key': api_key}
        self.logger = logging.getLogger(__name__)
    
    def _make_request(
        self,
        method: str,
        url: str,
        **kwargs
    ) -> Optional[requests.Response]:
        """
        Faz requisição com tratamento de erro e retry
        """
        max_retries = 3
        base_delay = 1.0
        
        for attempt in range(max_retries + 1):
            try:
                response = requests.request(
                    method=method,
                    url=url,
                    headers=self.base_headers,
                    timeout=30,
                    **kwargs
                )
                
                # Log da requisição
                self._log_request(response, attempt + 1)
                
                # Sucesso
                if response.status_code < 400:
                    return response
                
                # Tratamento de erros
                if not self._should_retry(response, attempt, max_retries):
                    return response
                
                # Aguardar antes do retry
                delay = self._calculate_delay(response, attempt, base_delay)
                time.sleep(delay)
                
            except requests.exceptions.RequestException as e:
                self.logger.error(f"Erro de conexão (tentativa {attempt + 1}): {e}")
                if attempt < max_retries:
                    delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
                    time.sleep(delay)
                else:
                    raise e
        
        return None
    
    def _should_retry(
        self,
        response: requests.Response,
        attempt: int,
        max_retries: int
    ) -> bool:
        """
        Determina se deve fazer retry
        """
        if attempt >= max_retries:
            return False
        
        # Retry para rate limit
        if response.status_code == 429:
            return True
        
        # Retry para erros 5xx
        if response.status_code >= 500:
            return True
        
        # Não fazer retry para outros erros
        return False
    
    def _calculate_delay(
        self,
        response: requests.Response,
        attempt: int,
        base_delay: float
    ) -> float:
        """
        Calcula delay para retry
        """
        if response.status_code == 429:
            # Usar Retry-After se disponível
            retry_after = response.headers.get('Retry-After')
            if retry_after:
                return int(retry_after)
        
        # Backoff exponencial com jitter
        return base_delay * (2 ** attempt) + random.uniform(0, 1)
    
    def _log_request(self, response: requests.Response, attempt: int) -> None:
        """
        Registra detalhes da requisição
        """
        if response.status_code >= 400:
            try:
                error_data = response.json().get('error', {})
                self.logger.error(
                    f"Erro API (tentativa {attempt}): "
                    f"Status {response.status_code}, "
                    f"Código: {error_data.get('code', 'UNKNOWN')}, "
                    f"Request ID: {error_data.get('request_id', 'N/A')}"
                )
            except:
                self.logger.error(
                    f"Erro API (tentativa {attempt}): Status {response.status_code}"
                )
        else:
            self.logger.info(f"Requisição bem-sucedida (tentativa {attempt})")

# Uso
client = JuditAPIClient(os.getenv('JUDIT_API_KEY'))
response = client._make_request('GET', 'https://requests.prod.judit.io/requests')

Próximos Passos

  • Rate Limits: Entenda os limites e como evitar erros 429
  • FAQ: Perguntas frequentes sobre erros comuns
Dica: Sempre implemente logging adequado e monitore os request_id para facilitar o suporte técnico.