Para integrar a API da CPFHub.io em uma aplicação Actix Web, crie um struct CpfClient que encapsula o reqwest::Client e a API key, registre-o como dado compartilhado com web::Data, e exponha um handler GET /api/cpf/{cpf} que faz a consulta e retorna o resultado serializado com serde. A latência é de ~900ms e o endpoint da CPFHub.io é GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key.
Introdução
O Actix Web é um dos frameworks web mais rápidos disponíveis, construído sobre o ecossistema Rust. Sua arquitetura baseada em actors e seu sistema de tipos robusto o tornam ideal para construir APIs de alta performance que consomem serviços externos como a CPFHub.io.
Configurando o projeto
Crie o projeto e adicione as dependências ao Cargo.toml:
// Cargo.toml
[package]
name = "cpf-actix-api"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4"
reqwest = { version = "0.12", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
dotenv = "0.15"
| Dependência | Finalidade |
|---|---|
actix-web | Framework web para servir endpoints HTTP |
reqwest | Cliente HTTP para consumir a API do CPFHub |
serde | Serialização e desserialização de dados |
dotenv | Carregamento de variáveis de ambiente |
Definindo os modelos
Crie structs para representar a resposta da API externa e a resposta que sua aplicação retornará:
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct CpfApiResponse {
pub success: bool,
pub data: CpfApiData,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CpfApiData {
pub cpf: String,
pub name: String,
pub name_upper: String,
pub gender: String,
pub birth_date: String,
pub day: String,
pub month: String,
pub year: String,
}
#[derive(Debug, Serialize)]
pub struct CpfResultado {
pub valido: bool,
pub cpf: String,
pub nome: Option<String>,
pub data_nascimento: Option<String>,
pub genero: Option<String>,
pub mensagem: String,
}
Criando o serviço de consulta
Encapsule a lógica de comunicação com a API em um módulo dedicado:
use reqwest::header::{HeaderMap, HeaderValue};
pub struct CpfClient {
http_client: reqwest::Client,
api_key: String,
}
impl CpfClient {
pub fn new(api_key: String) -> Self {
let http_client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.expect("Falha ao criar cliente HTTP");
Self { http_client, api_key }
}
pub async fn consultar(&self, cpf: &str) -> Result<CpfApiResponse, String> {
let mut headers = HeaderMap::new();
headers.insert(
"x-api-key",
HeaderValue::from_str(&self.api_key)
.map_err(|_| "Chave de API inválida".to_string())?,
);
let url = format!("https://api.cpfhub.io/cpf/{}", cpf);
let response = self.http_client
.get(&url)
.headers(headers)
.send()
.await
.map_err(|e| format!("Erro na requisição: {}", e))?;
if !response.status().is_success() {
return Err(format!("API retornou status: {}", response.status()));
}
response.json::<CpfApiResponse>()
.await
.map_err(|e| format!("Erro ao desserializar: {}", e))
}
}
Configurando os handlers do Actix Web
Crie os handlers que processam as requisições HTTP e utilizam o serviço de consulta:
use actix_web::{get, web, HttpResponse, Responder};
#[get("/api/cpf/{cpf}")]
async fn consultar_cpf(
path: web::Path<String>,
cpf_client: web::Data<CpfClient>,
) -> impl Responder {
let cpf = path.into_inner();
let cpf_limpo: String = cpf.chars().filter(|c| c.is_ascii_digit()).collect();
if cpf_limpo.len() != 11 {
return HttpResponse::BadRequest().json(CpfResultado {
valido: false,
cpf: cpf_limpo,
nome: None,
data_nascimento: None,
genero: None,
mensagem: "CPF deve conter 11 dígitos".to_string(),
});
}
match cpf_client.consultar(&cpf_limpo).await {
Ok(dados) if dados.success => {
HttpResponse::Ok().json(CpfResultado {
valido: true,
cpf: dados.data.cpf,
nome: Some(dados.data.name),
data_nascimento: Some(dados.data.birth_date),
genero: Some(dados.data.gender),
mensagem: "CPF encontrado com sucesso".to_string(),
})
}
Ok(_) => HttpResponse::NotFound().json(CpfResultado {
valido: false,
cpf: cpf_limpo,
nome: None,
data_nascimento: None,
genero: None,
mensagem: "CPF não encontrado".to_string(),
}),
Err(e) => HttpResponse::BadGateway().json(serde_json::json!({
"erro": e
})),
}
}
Montando a aplicação principal
Configure o servidor Actix Web com o serviço compartilhado e os endpoints:
use actix_web::{App, HttpServer};
use std::env;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
let api_key = env::var("CPFHUB_API_KEY")
.expect("CPFHUB_API_KEY deve estar definida");
let cpf_client = web::Data::new(CpfClient::new(api_key));
println!("Servidor iniciado em http://localhost:8080");
HttpServer::new(move || {
App::new()
.app_data(cpf_client.clone())
.service(consultar_cpf)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Perguntas frequentes
A CPFHub.io retorna HTTP 429 quando o volume de consultas é alto?
Não. A API da CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições por excesso de volume. Ao superar a cota mensal do plano, cada consulta adicional é cobrada automaticamente a R$0,15 — o servidor Actix Web continua recebendo respostas normalmente, sem necessidade de lógica de retry para rate limit.
Como compartilhar o CpfClient de forma segura entre múltiplos workers do Actix Web?
Use web::Data<CpfClient> para registrar o cliente como dado compartilhado no App. O Actix Web clona o Arc interno automaticamente para cada worker, garantindo que o pool de conexões do reqwest::Client seja reutilizado com eficiência. Consulte a documentação do Actix Web para detalhes sobre dados de aplicação compartilhados.
Como configurar timeout adequado para não travar o servidor durante consultas lentas?
Defina o timeout no builder do reqwest::Client com .timeout(Duration::from_secs(10)). Como a CPFHub.io responde em ~900ms, 10 segundos é uma margem segura. No handler do Actix Web, erros de timeout resultam em HttpResponse::BadGateway, o que sinaliza ao cliente que o problema é downstream, não no seu servidor.
Como estruturar testes de integração para o handler de consulta de CPF no Actix Web?
Use actix_web::test::init_service para inicializar um servidor de teste e test::call_service para enviar requisições. Injete um CpfClient com URL configurável por variável de ambiente para apontar para um mock ou para a API real em testes de integração. Isso mantém os testes unitários rápidos e os de integração isolados.
Conclusão
O Actix Web, combinado com reqwest, proporciona uma base sólida para construir APIs de consulta de CPF com altíssima performance em Rust. A segurança de tipos do Rust garante que erros sejam capturados em tempo de compilação, reduzindo bugs em produção. Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a construir sua integração Actix Web com a API de CPF 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.



