Criar um microsserviço de validação de CPF com Elixir e Phoenix combina a robustez do runtime BEAM com a API do CPFHub.io para entregar verificações de identidade confiáveis em produção. O resultado é um serviço isolado, tolerante a falhas e escalável horizontalmente que pode ser consumido por qualquer parte da sua arquitetura. A latência de resposta da API CPFHub.io fica em torno de 900ms, e o plano gratuito cobre 50 consultas mensais sem cartão de crédito.
Introdução
Microsserviços são ideais para encapsular funcionalidades específicas como a validação de CPF. Elixir, com Phoenix e o runtime da BEAM, oferece tolerância a falhas, concorrência massiva e hot-code reloading — características que tornam a plataforma perfeita para microsserviços em produção.
Estrutura do microsserviço
Crie o projeto Phoenix otimizado para API (sem assets e HTML):
# Criação do projeto
# mix phx.new cpf_service --no-html --no-assets --no-dashboard --no-mailer
# mix.exs
defp deps do
[
{:phoenix, "~> 1.7"},
{:tesla, "~> 1.8"},
{:hackney, "~> 1.20"},
{:jason, "~> 1.4"},
{:plug_cowboy, "~> 2.7"}
]
end
| Componente | Responsabilidade |
|---|---|
| Router | Roteamento de requisições HTTP |
| CpfController | Processamento de requisições de CPF |
| CpfContext | Lógica de negócio e validação |
| ApiClient | Comunicação com a API do CPFHub |
| HealthController | Endpoint de health check |
Implementando o context de CPF
O context encapsula toda a lógica de validação e consulta:
defmodule CpfService.Cpf do
alias CpfService.Cpf.{Validator, ApiClient}
def validar(cpf) do
cpf_limpo = limpar_cpf(cpf)
with :ok <- Validator.validar_formato(cpf_limpo),
:ok <- Validator.validar_digitos(cpf_limpo) do
{:ok, %{cpf: cpf_limpo, formato_valido: true, mensagem: "CPF válido"}}
end
end
def consultar(cpf) do
cpf_limpo = limpar_cpf(cpf)
with :ok <- Validator.validar_formato(cpf_limpo),
:ok <- Validator.validar_digitos(cpf_limpo),
{:ok, dados} <- ApiClient.consultar(cpf_limpo) do
{:ok, %{
cpf: cpf_limpo,
nome: dados["name"],
nome_upper: dados["nameUpper"],
genero: dados["gender"],
data_nascimento: dados["birthDate"],
dia: dados["day"],
mes: dados["month"],
ano: dados["year"]
}}
end
end
defp limpar_cpf(cpf), do: String.replace(cpf, ~r/\D/, "")
end
defmodule CpfService.Cpf.Validator do
def validar_formato(cpf) when byte_size(cpf) != 11, do: {:error, :formato_invalido}
def validar_formato(_cpf), do: :ok
def 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_invalidos}
end
end
end
defp calcular_digito(digitos, count, peso) do
soma = digitos |> Enum.take(count) |> Enum.with_index()
|> Enum.reduce(0, fn {d, i}, acc -> acc + d * (peso - i) end)
resto = rem(soma, 11)
if resto < 2, do: 0, else: 11 - resto
end
end
Cliente da API com Tesla
Configure o cliente HTTP com middlewares para resiliência. A documentação oficial do Tesla está disponível em hexdocs.pm/tesla:
defmodule CpfService.Cpf.ApiClient do
use Tesla
plug Tesla.Middleware.BaseUrl, "https://api.cpfhub.io"
plug Tesla.Middleware.JSON
plug Tesla.Middleware.Timeout, timeout: 10_000
plug Tesla.Middleware.Retry, delay: 500, max_retries: 2
def consultar(cpf) do
api_key = Application.get_env(:cpf_service, :cpfhub_api_key)
headers = [{"x-api-key", api_key}]
case get("/cpf/#{cpf}", headers: headers) do
{:ok, %{status: 200, body: %{"success" => true, "data" => data}}} ->
{:ok, data}
{:ok, %{status: 404}} ->
{:error, :nao_encontrado}
{:ok, %{status: 401}} ->
{:error, :nao_autorizado}
{:ok, %{status: status}} ->
{:error, {:status_inesperado, status}}
{:error, reason} ->
{:error, {:falha_conexao, reason}}
end
end
end
Rotas e controllers
Configure o router e os controllers do microsserviço:
defmodule CpfServiceWeb.Router do
use CpfServiceWeb, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", CpfServiceWeb do
pipe_through :api
get "/cpf/validar/:cpf", CpfController, :validar
get "/cpf/consultar/:cpf", CpfController, :consultar
get "/health", HealthController, :check
end
end
defmodule CpfServiceWeb.CpfController do
use CpfServiceWeb, :controller
alias CpfService.Cpf
def validar(conn, %{"cpf" => cpf}) do
case Cpf.validar(cpf) do
{:ok, resultado} ->
json(conn, %{success: true, data: resultado})
{:error, reason} ->
conn
|> put_status(:bad_request)
|> json(%{success: false, error: to_string(reason)})
end
end
def consultar(conn, %{"cpf" => cpf}) do
case Cpf.consultar(cpf) do
{:ok, dados} ->
json(conn, %{success: true, data: dados})
{:error, :nao_encontrado} ->
conn |> put_status(:not_found) |> json(%{success: false, error: "CPF não encontrado"})
{:error, :nao_autorizado} ->
conn |> put_status(:unauthorized) |> json(%{success: false, error: "Chave inválida"})
{:error, _reason} ->
conn |> put_status(:bad_gateway) |> json(%{success: false, error: "Erro na API externa"})
end
end
end
defmodule CpfServiceWeb.HealthController do
use CpfServiceWeb, :controller
def check(conn, _params) do
json(conn, %{
status: "ok",
service: "cpf-service",
timestamp: DateTime.utc_now() |> DateTime.to_iso8601(),
version: Application.spec(:cpf_service, :vsn) |> to_string()
})
end
end
Deploy com Docker
Prepare o microsserviço para deploy containerizado:
# Dockerfile
# Utilize a imagem oficial do Elixir
# FROM elixir:1.16-alpine AS builder
# Configuração de release no mix.exs
def project do
[
app: :cpf_service,
version: "1.0.0",
elixir: "~> 1.16",
releases: [
cpf_service: [
include_executables_for: [:unix],
applications: [runtime_tools: :permanent]
]
]
]
end
# config/runtime.exs
import Config
config :cpf_service, CpfServiceWeb.Endpoint,
url: [host: System.get_env("PHX_HOST") || "localhost"],
http: [port: String.to_integer(System.get_env("PORT") || "4000")],
server: true
config :cpf_service, :cpfhub_api_key, System.get_env("CPFHUB_API_KEY")
Perguntas frequentes
Como a API CPFHub.io se comporta quando o limite do plano gratuito é atingido?
A API nunca bloqueia requisições nem retorna HTTP 429. Quando o limite de 50 consultas mensais do plano gratuito é ultrapassado, cada consulta adicional é cobrada a R$0,15. Isso garante que o microsserviço continue funcionando sem interrupções, mesmo em meses com volume maior.
Qual é o formato da resposta da API CPFHub.io?
A API retorna um JSON com os campos success, e dentro de data: cpf, name, nameUpper, gender, birthDate, day, month e year. A autenticação é feita pelo header x-api-key em chamadas GET https://api.cpfhub.io/cpf/{CPF}.
Por que usar Elixir e Phoenix em vez de outras stacks para este microsserviço?
O runtime BEAM oferece isolamento de processos, supervisão automática e hot-code reloading. Uma falha em uma consulta de CPF não derruba as demais, o que é essencial em microsserviços de alta disponibilidade. A biblioteca Tesla facilita o gerenciamento de timeouts e retries sem boilerplate adicional.
Como configurar a chave de API em produção com segurança?
Nunca inclua a API key no código-fonte. Use variáveis de ambiente (ex: CPFHUB_API_KEY) lidas em config/runtime.exs e gerenciadas por ferramentas como Kubernetes Secrets, AWS Parameter Store ou Fly.io secrets. Rotacione a chave periodicamente pelo painel em cpfhub.io.
Conclusão
Um microsserviço de validação de CPF com Elixir e Phoenix oferece alta disponibilidade, tolerância a falhas e excelente performance. A arquitetura baseada em processos da BEAM garante que falhas em uma consulta não afetem as demais, e a integração com a API CPFHub.io traz dados cadastrais reais em cada verificação.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a construir seu microsserviço de validação de CPF com Elixir 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.



