Validar CPF em tempo real com Elixir combina dois passos: verificação algorítmica dos dígitos verificadores (< 0,1ms, sem rede) e consulta à API REST do CPFHub.io para confirmar os dados cadastrais (~900ms). O modelo de processos leves da BEAM VM permite executar centenas dessas validações em paralelo sem degradar a performance da aplicação.
Introdução
A validação de CPF em tempo real é crucial para garantir a qualidade dos dados em formulários de cadastro. Elixir, com seu modelo de concorrência baseado em processos leves, é ideal para esse tipo de operação que combina processamento local rápido com chamadas assíncronas a APIs externas.
Validação algorítmica do CPF
Implemente a verificação dos dígitos verificadores de forma funcional e idiomática em Elixir:
defmodule CpfValidator do
@moduledoc """
Módulo para validação algorítmica de CPF.
"""
@doc """
Valida os dígitos verificadores de um CPF.
"""
def validar(cpf) when is_binary(cpf) do
cpf
|> String.replace(~r/\D/, "")
|> validar_digitos()
end
defp validar_digitos(cpf) when byte_size(cpf) != 11, do: {:error, :tamanho_invalido}
defp validar_digitos(cpf) do
digitos = cpf |> String.graphemes() |> Enum.map(&String.to_integer/1)
if Enum.uniq(digitos) |> length() == 1 do
{:error, :digitos_repetidos}
else
d1 = calcular_digito(digitos, 9, 10)
d2 = calcular_digito(digitos, 10, 11)
if Enum.at(digitos, 9) == d1 and Enum.at(digitos, 10) == d2 do
:ok
else
{:error, :digitos_verificadores_invalidos}
end
end
end
defp calcular_digito(digitos, count, peso_inicial) do
soma =
digitos
|> Enum.take(count)
|> Enum.with_index()
|> Enum.reduce(0, fn {d, i}, acc -> acc + d * (peso_inicial - i) end)
resto = rem(soma, 11)
if resto < 2, do: 0, else: 11 - resto
end
end
Serviço de validação em tempo real
Combine a validação local com a consulta à API para fornecer um resultado completo:
defmodule CpfValidationService do
@moduledoc """
Serviço de validação de CPF em tempo real com consulta à API.
"""
alias CpfValidator
@base_url "https://api.cpfhub.io"
def validar_completo(cpf, api_key) do
cpf_limpo = String.replace(cpf, ~r/\D/, "")
with :ok <- CpfValidator.validar(cpf_limpo),
{:ok, dados} <- consultar_api(cpf_limpo, api_key) do
{:ok, %{
formato_valido: true,
encontrado: true,
nome: dados["name"],
data_nascimento: dados["birthDate"],
genero: dados["gender"],
mensagem: "CPF válido e encontrado na base"
}}
else
{:error, :tamanho_invalido} ->
{:error, %{formato_valido: false, mensagem: "CPF deve conter 11 dígitos"}}
{:error, :digitos_repetidos} ->
{:error, %{formato_valido: false, mensagem: "CPF com dígitos repetidos"}}
{:error, :digitos_verificadores_invalidos} ->
{:error, %{formato_valido: false, mensagem: "Dígitos verificadores inválidos"}}
{:error, :cpf_nao_encontrado} ->
{:ok, %{
formato_valido: true,
encontrado: false,
nome: nil,
data_nascimento: nil,
genero: nil,
mensagem: "CPF válido, porém não encontrado na base"
}}
{:error, reason} ->
{:error, %{formato_valido: true, mensagem: "Erro: #{inspect(reason)}"}}
end
end
defp consultar_api(cpf, api_key) do
headers = [{"x-api-key", api_key}]
url = "#{@base_url}/cpf/#{cpf}"
case HTTPoison.get(url, headers, recv_timeout: 5000) do
{:ok, %{status_code: 200, body: body}} ->
case Jason.decode!(body) do
%{"success" => true, "data" => data} -> {:ok, data}
_ -> {:error, :cpf_nao_encontrado}
end
{:ok, %{status_code: 404}} ->
{:error, :cpf_nao_encontrado}
{:error, reason} ->
{:error, {:falha_api, reason}}
end
end
end
| Etapa | Tempo | Recurso utilizado |
|---|---|---|
| Limpeza do CPF | < 0.1ms | Regex local |
| Validação de dígitos | < 0.1ms | Cálculo aritmético |
| Consulta à API | ~900ms | HTTP via rede |
| Resposta total | ~900ms | Resultado combinado |
Integrando com LiveView para feedback instantâneo
O Phoenix LiveView permite validação em tempo real com feedback visual imediato:
defmodule MinhaAppWeb.CpfValidationLive do
use MinhaAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket,
cpf_input: "",
validacao_local: nil,
resultado_api: nil,
loading: false
)}
end
def handle_event("validar_local", %{"cpf" => cpf}, socket) do
resultado = CpfValidator.validar(cpf)
{:noreply, assign(socket, cpf_input: cpf, validacao_local: resultado)}
end
def handle_event("consultar_api", %{"cpf" => cpf}, socket) do
socket = assign(socket, loading: true)
api_key = Application.get_env(:minha_app, :cpfhub)[:api_key]
case CpfValidationService.validar_completo(cpf, api_key) do
{:ok, resultado} ->
{:noreply, assign(socket, resultado_api: resultado, loading: false)}
{:error, resultado} ->
{:noreply, assign(socket, resultado_api: resultado, loading: false)}
end
end
def render(assigns) do
~H"""
<div class="max-w-md mx-auto">
<h2>Validação de CPF</h2>
<form phx-change="validar_local" phx-submit="consultar_api">
<input type="text" name="cpf" value={@cpf_input}
placeholder="000.000.000-00" maxlength="14"
class="form-input w-full" />
<button type="submit" disabled={@loading} class="btn mt-2">
<%= if @loading, do: "Consultando...", else: "Consultar" %>
</button>
</form>
<%= if @resultado_api do %>
<div class="mt-4 p-4 border rounded">
<p><strong>Status:</strong> <%= @resultado_api.mensagem %></p>
<%= if @resultado_api[:nome] do %>
<p><strong>Nome:</strong> <%= @resultado_api.nome %></p>
<p><strong>Nascimento:</strong> <%= @resultado_api.data_nascimento %></p>
<% end %>
</div>
<% end %>
</div>
"""
end
end
Adicionando cache com ETS
Para evitar consultas repetidas, utilize ETS como cache em memória:
defmodule CpfCache do
use GenServer
@table_name :cpf_cache
@ttl_seconds 600
def start_link(_opts) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
:ets.new(@table_name, [:named_table, :public, read_concurrency: true])
{:ok, %{}}
end
def get(cpf) do
case :ets.lookup(@table_name, cpf) do
[{^cpf, resultado, timestamp}] ->
if System.system_time(:second) - timestamp < @ttl_seconds do
{:ok, resultado}
else
:ets.delete(@table_name, cpf)
:miss
end
[] -> :miss
end
end
def put(cpf, resultado) do
:ets.insert(@table_name, {cpf, resultado, System.system_time(:second)})
:ok
end
end
Perguntas frequentes
Por que separar a validação algorítmica da consulta à API em Elixir?
A validação algorítmica (dígitos verificadores) é local e executa em menos de 0,1ms — ela elimina CPFs estruturalmente inválidos antes de qualquer chamada de rede. Isso evita consumo desnecessário de quota da API e reduz a latência para entradas inválidas. Apenas CPFs que passam na validação local disparam a consulta HTTP ao CPFHub.io.
Como processar múltiplas validações de CPF em paralelo com Elixir?
Use Task.async_stream/3 para paralelizar as consultas dentro do limite de concorrência desejado. A BEAM VM agenda os processos leves de forma eficiente, e cada consulta à API (~900ms) é executada de forma independente. Para cenários de alta escala, considere Oban para gerenciar filas de validação em background.
A API CPFHub.io retorna HTTP 429 quando o limite é atingido?
Não. A CPFHub.io não bloqueia e não retorna erro 429: consultas excedentes são cobradas a R$ 0,15 cada. O plano gratuito oferece 50 consultas mensais sem cartão de crédito; o plano Pro inclui 1.000 consultas por R$ 149/mês. Isso simplifica o tratamento de erros no código Elixir — não é necessário lidar com backoff por limite de taxa.
Como garantir conformidade com a LGPD ao usar a API de CPF em aplicações Elixir?
Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não persista o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A ANPD orienta que dados de identificação devem ser tratados com o princípio da necessidade.
Conclusão
A validação de CPF em tempo real com Elixir combina a eficiência da BEAM VM com a riqueza de dados da API. O modelo de concorrência do Elixir permite processar múltiplas validações simultaneamente sem degradação de performance, e o cache com ETS elimina consultas redundantes.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a validação de CPF na sua aplicação Elixir com dados cadastrais reais em produção.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
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.



