Para integrar validação de CPF em Elixir com Phoenix LiveView, adicione httpoison e jason ao mix.exs, crie um módulo CpfHub que chama GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key, e dispare a consulta de forma assíncrona com send(self(), {:consultar_cpf, cpf}) no handle_event. O resultado aparece na interface via WebSocket sem recarregar a página.
Introdução
O Elixir, combinado com o framework Phoenix, é uma plataforma cada vez mais adotada para construção de aplicações web de alta concorrência. O Phoenix LiveView leva essa proposta ainda mais longe, permitindo criar interfaces interativas em tempo real sem escrever JavaScript, utilizando WebSockets para comunicação bidirecional entre servidor e cliente.
Para aplicações brasileiras que precisam validar CPF durante o cadastro ou onboarding de usuários, o LiveView oferece uma experiência fluida: o usuário digita o CPF, o servidor faz a consulta à API e o resultado aparece na tela instantaneamente, sem recarregar a página.
Pré-requisitos
- Elixir 1.15+ — Instalado via asdf ou brew.
- Phoenix 1.7+ — Com LiveView configurado.
- Conta na CPFHub.io — Para obter a chave de API (50 consultas/mês no plano gratuito).
Adicionando dependências no mix.exs
defp deps do
[
{:phoenix, "~> 1.7"},
{:phoenix_live_view, "~> 0.20"},
{:httpoison, "~> 2.2"},
{:jason, "~> 1.4"}
]
end
Execute mix deps.get para instalar as dependências.
Módulo de consulta à API
Crie um módulo dedicado para a comunicação com a API da CPFHub.io:
defmodule MeuApp.CpfHub do
@moduledoc """
Módulo para consulta de CPF via API da CPFHub.io.
"""
@base_url "https://api.cpfhub.io/cpf/"
@timeout 10_000
def consultar(cpf) when is_binary(cpf) do
cpf_limpo = String.replace(cpf, ~r/\D/, "")
case String.length(cpf_limpo) do
11 -> fazer_requisicao(cpf_limpo)
_ -> {:error, :cpf_invalido}
end
end
defp fazer_requisicao(cpf) do
url = @base_url <> cpf
headers = [
{"x-api-key", api_key()},
{"Accept", "application/json"}
]
options = [
timeout: @timeout,
recv_timeout: @timeout
]
case HTTPoison.get(url, headers, options) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
processar_resposta(body)
{:ok, %HTTPoison.Response{status_code: 401}} ->
{:error, :chave_invalida}
{:ok, %HTTPoison.Response{status_code: status}} ->
{:error, {:http_error, status}}
{:error, %HTTPoison.Error{reason: :timeout}} ->
{:error, :timeout}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, {:request_error, reason}}
end
end
defp processar_resposta(body) do
case Jason.decode(body) do
{:ok, %{"success" => true, "data" => data}} ->
{:ok, %{
cpf: data["cpf"],
nome: data["name"],
nome_upper: data["nameUpper"],
genero: data["gender"],
data_nascimento: data["birthDate"],
dia: data["day"],
mes: data["month"],
ano: data["year"]
}}
{:ok, %{"success" => false}} ->
{:error, :cpf_nao_encontrado}
{:error, _} ->
{:error, :json_invalido}
end
end
defp api_key do
Application.get_env(:meu_app, :cpfhub_api_key, "SUA_CHAVE_DE_API")
end
end
A API da CPFHub.io não retorna HTTP 429 ao atingir o limite de consultas do plano — ela continua respondendo normalmente e cobra R$ 0,15 por consulta excedente. Por isso o código acima não trata esse status code; trate o código 401 (chave inválida) e erros de rede como casos prioritários.
Configuração da chave de API
No arquivo config/runtime.exs:
config :meu_app, :cpfhub_api_key, System.get_env("CPFHUB_API_KEY")
Implementando o LiveView
Crie o LiveView que gerencia a consulta interativa de CPF:
defmodule MeuAppWeb.CpfLive do
use MeuAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket,
cpf_input: "",
resultado: nil,
erro: nil,
carregando: false
)}
end
def handle_event("validar_cpf", %{"cpf" => cpf}, socket) do
cpf_limpo = String.replace(cpf, ~r/\D/, "")
if String.length(cpf_limpo) != 11 do
{:noreply, assign(socket,
erro: "Informe um CPF com 11 dígitos.",
resultado: nil
)}
else
socket = assign(socket, carregando: true, erro: nil, resultado: nil)
send(self(), {:consultar_cpf, cpf_limpo})
{:noreply, socket}
end
end
def handle_event("atualizar_cpf", %{"cpf" => cpf}, socket) do
{:noreply, assign(socket, cpf_input: cpf)}
end
def handle_info({:consultar_cpf, cpf}, socket) do
case MeuApp.CpfHub.consultar(cpf) do
{:ok, dados} ->
{:noreply, assign(socket,
resultado: dados,
erro: nil,
carregando: false
)}
{:error, :cpf_invalido} ->
{:noreply, assign(socket,
erro: "CPF inválido.",
carregando: false
)}
{:error, :cpf_nao_encontrado} ->
{:noreply, assign(socket,
erro: "CPF não encontrado na base de dados.",
carregando: false
)}
{:error, :timeout} ->
{:noreply, assign(socket,
erro: "A consulta excedeu o tempo limite.",
carregando: false
)}
{:error, _} ->
{:noreply, assign(socket,
erro: "Erro ao consultar CPF.",
carregando: false
)}
end
end
def render(assigns) do
~H"""
<div class="max-w-md mx-auto mt-10">
<h1 class="text-2xl font-bold mb-6">Consulta de CPF</h1>
<form phx-submit="validar_cpf" phx-change="atualizar_cpf">
<input
type="text"
name="cpf"
value={@cpf_input}
placeholder="Digite o CPF"
maxlength="11"
class="w-full p-3 border rounded mb-4"
/>
<button
type="submit"
disabled={@carregando}
class="w-full bg-blue-600 text-white p-3 rounded"
>
<%= if @carregando, do: "Consultando...", else: "Consultar" %>
</button>
</form>
<%= if @resultado do %>
<div class="mt-6 p-4 bg-gray-100 rounded">
<p><strong>Nome:</strong> <%= @resultado.nome %></p>
<p><strong>CPF:</strong> <%= @resultado.cpf %></p>
<p><strong>Nascimento:</strong> <%= @resultado.data_nascimento %></p>
<p><strong>Gênero:</strong> <%= @resultado.genero %></p>
</div>
<% end %>
<%= if @erro do %>
<p class="mt-4 text-red-600"><%= @erro %></p>
<% end %>
</div>
"""
end
end
Rota no router
Adicione a rota no router.ex:
scope "/", MeuAppWeb do
pipe_through :browser
live "/consulta-cpf", CpfLive
end
Testando com cURL
Para testar a API diretamente:
curl -X GET https://api.cpfhub.io/cpf/12345678900 \
-H "x-api-key: SUA_CHAVE_DE_API" \
-H "Accept: application/json" \
--max-time 10
Resposta esperada:
{
"success": true,
"data": {
"cpf": "12345678900",
"name": "João da Silva",
"nameUpper": "JOÃO DA SILVA",
"gender": "M",
"birthDate": "15/06/1990",
"day": 15,
"month": 6,
"year": 1990
}
}
Vantagens do Elixir e LiveView para validação de CPF
-
Concorrência — A BEAM VM do Elixir gerencia milhares de processos simultâneos, ideal para serviços de validação com alto volume.
-
Tempo real — O LiveView atualiza a interface via WebSocket sem necessidade de JavaScript customizado, proporcionando feedback instantâneo.
-
Tolerância a falhas — O modelo de supervisão do Elixir permite que falhas em uma consulta não afetem o restante da aplicação.
-
Pattern matching — O tratamento de erros com pattern matching torna o código expressivo e fácil de manter.
Boas práticas
-
Timeout — Configure timeout no HTTPoison para evitar processos bloqueados indefinidamente.
-
Chave de API — Armazene em variáveis de ambiente e acesse via
Application.get_env/3. -
Consulta assíncrona — No LiveView, envie a consulta com
send(self(), ...)para não bloquear o processo do LiveView enquanto aguarda a resposta da API. -
Plano gratuito — O plano gratuito da CPFHub.io inclui 50 consultas/mês. O plano Pro oferece 1.000 consultas por R$ 149/mês, com R$ 0,15 por consulta adicional sem bloqueio do serviço.
Perguntas frequentes
Por que usar send(self(), {:consultar_cpf, cpf}) em vez de chamar a API diretamente no handle_event?
Chamar a API diretamente no handle_event bloquearia o processo do LiveView durante toda a latência da requisição — cerca de 900ms no caso da CPFHub.io. Durante esse tempo, o processo não consegue responder a outros eventos do usuário. Ao usar send(self(), ...), a consulta é delegada para handle_info e o LiveView pode imediatamente devolver uma resposta ao cliente (mostrando "Consultando..."), mantendo a interface responsiva.
Como configurar a chave de API da CPFHub.io de forma segura em Elixir?
Armazene a chave em variável de ambiente (CPFHUB_API_KEY) e leia no config/runtime.exs com System.get_env("CPFHUB_API_KEY"). Nunca coloque a chave em config/config.exs ou config/dev.exs se esses arquivos são versionados no repositório. Em produção, use o mecanismo de secrets da sua plataforma (Fly.io secrets, Heroku config vars, AWS Secrets Manager).
A API da CPFHub.io bloqueia requisições quando o limite do plano é atingido?
Não. A API não retorna HTTP 429 nem bloqueia requisições ao atingir o limite mensal. Ela continua respondendo normalmente e cobra R$ 0,15 por consulta que exceder o volume contratado. Por isso o módulo Elixir não precisa tratar 429 — trate apenas erros reais como 401 (chave inválida), timeout de rede e falhas de parsing JSON.
Como testar a integração com Elixir sem consumir consultas do plano de produção?
Crie uma conta separada na CPFHub.io para ambiente de desenvolvimento e use a chave dessa conta nas variáveis de ambiente de dev. Alternativamente, escreva um mock do módulo CpfHub usando Mox ou Bypass nos testes automatizados — assim você valida o comportamento do LiveView sem fazer chamadas reais à API.
Conclusão
Integrar a validação de CPF em aplicações Elixir com Phoenix LiveView é uma combinação poderosa que oferece interatividade em tempo real, alta concorrência e tolerância a falhas. Com a API da CPFHub.io, o processo de validação fica pronto em menos de 30 minutos e escala sem esforço adicional.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e adicione validação de CPF em tempo real ao seu LiveView hoje mesmo.
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.



