Como Lidar com Erros Comuns ao Consumir APIs de CPF em Ruby

Aprenda a lidar com erros comuns ao consumir APIs de CPF em Ruby, incluindo timeouts, rate limiting, erros de rede e respostas inesperadas.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como Lidar com Erros Comuns ao Consumir APIs de CPF em Ruby

Consumir APIs externas é uma operação inerentemente frágil: timeouts, erros de rede, rate limiting e respostas inesperadas são situações que toda aplicação deve estar preparada para enfrentar. Em Ruby, a forma como esses erros são tratados pode significar a diferença entre uma aplicação resiliente e uma que falha silenciosamente ou trava completamente.

Introdução

Ao integrar uma API de CPF em produção, erros acontecem — e a maioria deles é previsível. Classificar cada tipo de falha e definir a resposta correta (retentar, registrar ou rejeitar) é o que separa um cliente HTTP ingênuo de uma integração confiável. Este guia apresenta o catálogo completo de erros e a implementação Ruby para tratá-los com segurança.

Catálogo de erros comuns

Os erros ao consumir APIs podem ser agrupados em categorias com tratamentos distintos.

Código HTTPTipo de ErroCausa ProvávelAção Recomendada
400Bad RequestCPF em formato inválidoCorrigir input, não retentar
401UnauthorizedAPI key inválida ou ausenteVerificar configuração, não retentar
403ForbiddenPlano sem acesso a este recursoVerificar plano, não retentar
404Not FoundCPF não encontrado na baseRegistrar, não retentar
429Too Many RequestsRate limit excedidoAguardar e retentar com backoff
500Internal Server ErrorErro interno da APIRetentar com backoff
502/503Bad Gateway / UnavailableAPI temporariamente indisponívelRetentar com backoff
TimeoutTimeoutRede lenta ou API sobrecarregadaRetentar com timeout maior

Erros de cliente (4xx) -- geralmente não devem ser retentados pois o problema está na requisição.

Erros de servidor (5xx) -- são transitórios e devem ser retentados com backoff exponencial.

Erros de rede -- timeout, connection refused e DNS failure exigem retry com estratégia de backoff. A OWASP recomenda tratar cada classe de erro de forma distinta para evitar que retentativas cegamente agravem uma situação de sobrecarga no servidor.


Classe de exceções customizadas

Definir exceções customizadas permite tratamento granular em diferentes partes da aplicação.

module CpfHub
    class Error < StandardError; end

    class ApiError < Error
    attr_reader :status_code, :response_body

    def initialize(message, status_code: nil, response_body: nil)
    @status_code = status_code
    @response_body = response_body
    super(message)
    end
    end

    class CpfInvalidoError < ApiError; end
    class AuthenticationError < ApiError; end
    class RateLimitError < ApiError
    attr_reader :retry_after

    def initialize(message, retry_after: 60, **kwargs)
    @retry_after = retry_after
    super(message, **kwargs)
    end
    end

    class CpfNaoEncontradoError < ApiError; end
    class ServerError < ApiError; end
    class TimeoutError < Error; end
    class NetworkError < Error; end
end

Cliente HTTP com tratamento robusto de erros

Implemente um cliente que mapeia cada tipo de resposta para a exceção apropriada.

require "faraday"
require "json"

module CpfHub
    class Client
    BASE_URL = "https://api.cpfhub.io"

    def initialize(api_key: ENV["CPFHUB_API_KEY"])
    @api_key = api_key
    @connection = build_connection
    end

    def consultar(cpf)
    cpf_limpo = cpf.to_s.gsub(/\D/, "")
    validar_formato_cpf!(cpf_limpo)

    resposta = @connection.get("/cpf/#{cpf_limpo}")
    tratar_resposta(resposta, cpf_limpo)
    rescue Faraday::TimeoutError => e
    raise CpfHub::TimeoutError,
    "Timeout ao consultar CPF: #{e.message}"
    rescue Faraday::ConnectionFailed => e
    raise CpfHub::NetworkError,
    "Falha de conexao: #{e.message}"
    end

    private

    def build_connection
    Faraday.new(url: BASE_URL) do |conn|
    conn.headers["x-api-key"] = @api_key
    conn.headers["Content-Type"] = "application/json"
    conn.options.timeout = 10
    conn.options.open_timeout = 5
    conn.adapter Faraday.default_adapter
    end
    end

    def validar_formato_cpf!(cpf)
    unless cpf.match?(/\A\d{11}\z/)
    raise CpfHub::CpfInvalidoError.new(
    "CPF deve conter exatamente 11 digitos",
    status_code: 400
    )
    end
    end

    def tratar_resposta(resposta, cpf)
    case resposta.status
    when 200
    body = JSON.parse(resposta.body)
    return body["data"] if body["success"]

    raise CpfHub::CpfNaoEncontradoError.new(
    "CPF #{cpf} nao encontrado",
    status_code: 200,
    response_body: resposta.body
    )
    when 401
    raise CpfHub::AuthenticationError.new(
    "API key invalida ou ausente",
    status_code: 401
    )
    when 429
    retry_after = resposta.headers["Retry-After"]&.to_i || 60
    raise CpfHub::RateLimitError.new(
    "Rate limit excedido",
    status_code: 429,
    retry_after: retry_after
    )
    when 500..599
    raise CpfHub::ServerError.new(
    "Erro interno da API (#{resposta.status})",
    status_code: resposta.status,
    response_body: resposta.body
    )
    else
    raise CpfHub::ApiError.new(
    "Resposta inesperada (#{resposta.status})",
    status_code: resposta.status,
    response_body: resposta.body
    )
    end
    end
    end
end

Retry com backoff exponencial

Implemente retry inteligente que trata cada tipo de erro de forma diferente.

module CpfHub
    class ResilientClient
    MAX_RETRIES = 3

    def initialize
    @client = Client.new
    end

    def consultar(cpf)
    tentativa = 0

    begin
    tentativa += 1
    @client.consultar(cpf)
    rescue CpfHub::RateLimitError => e
    if tentativa <= MAX_RETRIES
    delay = e.retry_after || (2**tentativa)
    log_retry(cpf, tentativa, delay, e)
    sleep(delay)
    retry
    end
    raise
    rescue CpfHub::ServerError, CpfHub::TimeoutError,
    CpfHub::NetworkError => e
    if tentativa <= MAX_RETRIES
    delay = (2**tentativa) + rand(0.0..1.0)
    log_retry(cpf, tentativa, delay, e)
    sleep(delay)
    retry
    end
    raise
    rescue CpfHub::CpfInvalidoError,
    CpfHub::AuthenticationError,
    CpfHub::CpfNaoEncontradoError
    raise # Não retentar erros de cliente
    end
    end

    private

    def log_retry(cpf, tentativa, delay, erro)
    puts "[CpfHub] Tentativa #{tentativa}/#{MAX_RETRIES} " \
    "para CPF #{cpf}. Retentando em #{delay.round(1)}s. " \
    "Erro: #{erro.class} - #{erro.message}"
    end
    end
end
Tipo de ErroRetentarDelayMáximo de Tentativas
CpfInvalidoErrorNãoN/AN/A
AuthenticationErrorNãoN/AN/A
CpfNaoEncontradoErrorNãoN/AN/A
RateLimitErrorSimRetry-After header3
ServerErrorSimExponencial + jitter3
TimeoutErrorSimExponencial + jitter3
NetworkErrorSimExponencial + jitter3

Uso prático com tratamento de erros

Veja como consumir o cliente resiliente na aplicação, tratando cada cenário de erro.

cliente = CpfHub::ResilientClient.new

begin
    dados = cliente.consultar("12345678901")
    puts "Nome: #{dados['name']}"
    puts "Data de nascimento: #{dados['birthDate']}"
rescue CpfHub::CpfInvalidoError => e
    puts "CPF em formato invalido: #{e.message}"
rescue CpfHub::CpfNaoEncontradoError => e
    puts "CPF nao encontrado na base de dados"
rescue CpfHub::AuthenticationError => e
    puts "Erro de autenticacao. Verifique a API key."
    # Notificar equipe de operações
rescue CpfHub::RateLimitError => e
    puts "Limite de requisicoes excedido. Tente novamente em #{e.retry_after}s"
rescue CpfHub::ServerError => e
    puts "API temporariamente indisponivel (#{e.status_code})"
    # Registrar para monitoramento
rescue CpfHub::TimeoutError => e
    puts "Timeout na consulta. Verifique a conectividade."
rescue CpfHub::NetworkError => e
    puts "Erro de rede: #{e.message}"
end

Perguntas frequentes

Quando devo retentar uma requisição e quando devo falhar imediatamente?

Erros de servidor (5xx) e erros de rede (timeout, connection refused) são transitórios e devem ser retentados com backoff exponencial — até 3 tentativas é o padrão seguro. Erros de cliente (4xx) indicam problema na requisição em si e nunca devem ser retentados: corrigir o input é o caminho certo.

Como tratar o caso em que o CPF não é encontrado na API?

Um CPF não encontrado retorna HTTP 200 com success: false. Isso não é um erro de rede — é uma resposta válida indicando que o CPF não existe na base. O comportamento correto é registrar o resultado, não retentar, e bloquear o fluxo conforme a regra de negócio (ex: não emitir boleto, não aprovar cadastro).

O que fazer quando a API CPFHub.io retorna erro 429?

A CPFHub.io não bloqueia o acesso quando o limite mensal do plano é atingido — cobra R$0,15 por consulta adicional. O erro 429 é uma resposta temporária de rate limiting por volume de requisições simultâneas. A resposta deve incluir o header Retry-After com o tempo de espera; use esse valor no backoff antes de retentar.

Como proteger a API key em uma aplicação Ruby?

Armazene a chave em variável de ambiente (ENV["CPFHUB_API_KEY"]) e nunca a inclua no código-fonte ou em logs. Em Rails, use o credentials.yml.enc ou uma gem como dotenv para desenvolvimento local. Garanta também que os logs de requisição mascarem o número do CPF antes de gravar, conforme orientações de segurança em APIs REST.


Conclusão

O tratamento robusto de erros ao consumir APIs de CPF em Ruby é fundamental para construir aplicações resilientes. Exceções customizadas, retry inteligente com backoff exponencial e classificação correta dos erros garantem que a aplicação se recupere de falhas transitórias e falhe de forma informativa quando o problema está na requisição. Implementar essas práticas desde o início do projeto evita surpresas em produção e melhora significativamente a confiabilidade do sistema.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a construir sua integração Ruby com tratamento de erros robusto desde o primeiro deploy.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp