# 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.

**Publicado:** 22/03/2025
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-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

```elixir
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:

```elixir
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`:

```elixir
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:

```elixir
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`:

```elixir
scope "/", MeuAppWeb do
 pipe_through :browser

 live "/consulta-cpf", CpfLive
end
```

---

## Testando com cURL

Para testar a API diretamente:

```bash
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:

```json
{
 "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.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)

---

## 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](https://www.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.

