Como integrar validação de CPF em Elixir com Phoenix LiveView

Aprenda a integrar a validação de CPF via API em aplicações Elixir com Phoenix LiveView usando HTTPoison e Jason com exemplos completos.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como integrar validação de CPF em Elixir com Phoenix LiveView

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.

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