# Como consumir a API de CPF em Rust usando reqwest

> Aprenda a consumir a API de consulta de CPF em Rust usando a crate reqwest. Guia completo com exemplos práticos e tratamento de erros.

**Publicado:** 25/10/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-consumir-api-cpf-rust-reqwest

---


Para consumir a API de CPF da CPFHub.io em Rust, use a crate `reqwest` com suporte a JSON e o runtime assíncrono `tokio`. A chamada é um `GET https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`, e a resposta retorna nome, data de nascimento e gênero em cerca de 900ms. O `serde` cuida da desserialização para structs tipadas, tornando a integração segura e previsível.

## Introdução

Rust é uma linguagem conhecida por sua segurança de memória e performance excepcional. A crate `reqwest` é a escolha mais popular para realizar requisições HTTP em Rust, oferecendo uma API ergonômica tanto síncrona quanto assíncrona. Este guia mostra como consumir a API da CPFHub.io usando `reqwest` com tipagem forte e tratamento robusto de erros.

---

## Configurando o projeto Rust

Crie um novo projeto e adicione as dependências necessárias no `Cargo.toml`:

```rust
// Cargo.toml
[package]
name = "cpf-consulta"
version = "0.1.0"
edition = "2021"

[dependencies]
reqwest = { version = "0.12", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
```

A combinação de `reqwest` para HTTP, `serde` para serialização e `tokio` como runtime assíncrono forma a base de qualquer cliente HTTP em Rust.

---

## Definindo as estruturas de dados

Utilize `serde` para mapear a resposta JSON da API em structs Rust com tipagem forte:

```rust
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub struct CpfResponse {
 pub success: bool,
 pub data: CpfData,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CpfData {
 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,
}
```

| Campo na API | Campo na Struct | Tipo Rust |
|---|---|---|
| `cpf` | `cpf` | `String` |
| `name` | `name` | `String` |
| `nameUpper` | `name_upper` | `String` |
| `gender` | `gender` | `String` |
| `birthDate` | `birth_date` | `String` |
| `day` | `day` | `String` |
| `month` | `month` | `String` |
| `year` | `year` | `String` |

---

## Realizando a consulta HTTP

Crie uma função assíncrona que realiza a consulta à API com os headers necessários:

```rust
use reqwest::header::{HeaderMap, HeaderValue};
use std::error::Error;

async fn consultar_cpf(cpf: &str, api_key: &str) -> Result<CpfResponse, Box<dyn Error>> {
 let mut headers = HeaderMap::new();
 headers.insert("x-api-key", HeaderValue::from_str(api_key)?);

 let client = reqwest::Client::new();
 let url = format!("https://api.cpfhub.io/cpf/{}", cpf);

 let response = client
 .get(&url)
 .headers(headers)
 .send()
 .await?
 .error_for_status()?;

 let cpf_response = response.json::<CpfResponse>().await?;
 Ok(cpf_response)
}
```

---

## Tratamento de erros idiomático

Em Rust, o tratamento de erros é feito de forma explícita. Crie um tipo de erro customizado para lidar com os diferentes cenários de falha:

```rust
use std::fmt;

#[derive(Debug)]
pub enum CpfError {
 RequisicaoFalhou(reqwest::Error),
 CpfNaoEncontrado,
 ChaveInvalida,
 ErroDesconhecido(u16),
}

impl fmt::Display for CpfError {
 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 match self {
 CpfError::RequisicaoFalhou(e) => write!(f, "Erro na requisição: {}", e),
 CpfError::CpfNaoEncontrado => write!(f, "CPF não encontrado na base"),
 CpfError::ChaveInvalida => write!(f, "Chave de API inválida"),
 CpfError::ErroDesconhecido(code) => write!(f, "Erro HTTP: {}", code),
 }
 }
}

impl std::error::Error for CpfError {}

async fn consultar_cpf_seguro(
 cpf: &str,
 api_key: &str,
) -> Result<CpfResponse, CpfError> {
 let mut headers = HeaderMap::new();
 headers.insert(
 "x-api-key",
 HeaderValue::from_str(api_key).map_err(|_| CpfError::ChaveInvalida)?,
 );

 let client = reqwest::Client::new();
 let url = format!("https://api.cpfhub.io/cpf/{}", cpf);

 let response = client
 .get(&url)
 .headers(headers)
 .send()
 .await
 .map_err(CpfError::RequisicaoFalhou)?;

 match response.status().as_u16() {
 200 => {
 let dados = response.json::<CpfResponse>().await
 .map_err(CpfError::RequisicaoFalhou)?;
 Ok(dados)
 }
 401 => Err(CpfError::ChaveInvalida),
 404 => Err(CpfError::CpfNaoEncontrado),
 // Nota: a CPFHub.io não retorna 429; ao superar a cota, cobra R$0,15/consulta extra
 code => Err(CpfError::ErroDesconhecido(code)),
 }
}
```

---

## Exemplo completo com Tokio

Monte o programa principal utilizando o runtime `tokio`:

```rust
#[tokio::main]
async fn main() {
 let api_key = "SUA_API_KEY";
 let cpf = "12345678900";

 match consultar_cpf_seguro(cpf, api_key).await {
 Ok(resultado) => {
 println!("CPF encontrado com sucesso!");
 println!(" Nome: {}", resultado.data.name);
 println!(" CPF: {}", resultado.data.cpf);
 println!(" Nascimento: {}", resultado.data.birth_date);
 println!(" Gênero: {}", resultado.data.gender);
 }
 Err(CpfError::CpfNaoEncontrado) => {
 println!("O CPF informado não foi encontrado.");
 }
 Err(CpfError::ChaveInvalida) => {
 println!("Chave de API inválida. Verifique suas credenciais.");
 }
 Err(e) => {
 eprintln!("Erro inesperado: {}", e);
 }
 }
}
```

---

## Perguntas frequentes

### A CPFHub.io retorna erro 429 quando o limite de consultas é atingido?
Não. A API da CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições. Ao superar a cota mensal (50 no plano gratuito, 1.000 no plano Pro), cada consulta adicional é cobrada automaticamente a R$0,15 — o serviço continua respondendo normalmente. Por isso, o tratamento de erro no código Rust não precisa contemplar esse status.

### Como desserializar corretamente o JSON da CPFHub.io em Rust com serde?
Use `#[serde(rename_all = "camelCase")]` na struct de dados para mapear campos como `nameUpper` e `birthDate` automaticamente para `name_upper` e `birth_date`. O campo `success` fica na struct raiz e `data` é uma struct aninhada. Consulte a [documentação do serde](https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html) para padrões avançados de desserialização.

### Qual é o tempo de resposta típico da API ao fazer requisições com reqwest?
A CPFHub.io responde em aproximadamente 900ms. Configure o timeout do cliente `reqwest` para pelo menos 10 segundos para evitar interrupções em condições normais de rede. Use `.timeout(std::time::Duration::from_secs(10))` no builder do cliente.

### Como organizar o cliente HTTP em uma aplicação maior em Rust?
Crie um struct `CpfClient` que encapsula o `reqwest::Client` e a API key, então registre-o como dado compartilhado (por exemplo, `Arc<CpfClient>`) entre as tarefas assíncronas. Isso evita criar um novo cliente a cada requisição e garante reutilização do pool de conexões TCP.

### Leia também

- [Como consumir API de CPF em Rust com reqwest e serde](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-rust-com-reqwest-e-serde)
- [Como integrar a API de CPF em uma aplicação Rust com Actix Web](https://cpfhub.io/blog/como-integrar-api-cpf-rust-actix-web)
- [Como validar CPF em tempo real usando Rust e APIs REST](https://cpfhub.io/blog/como-validar-cpf-tempo-real-rust-apis-rest)
- [Como processar consultas de CPF de forma assíncrona em Rust com Tokio](https://cpfhub.io/blog/como-processar-consultas-cpf-assincrono-rust-tokio)

---

## Conclusão

Consumir a API de CPF em Rust com `reqwest` resulta em código performático, seguro e com tratamento de erros explícito. A tipagem forte do Rust, combinada com `serde` para desserialização, garante que os dados da API sejam manipulados de forma confiável. Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a integrar consultas de CPF em sua aplicação Rust em menos de 30 minutos.

