# Como integrar validação de CPF em Express.js com middleware customizado

> Aprenda a integrar a API de consulta de CPF da CPFHub.io em Express.js criando middlewares customizados para validação, cache e rate limiting.

**Publicado:** 04/06/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-express-js-com-middleware-customizado

---

O **Express.js** é o framework Node.js mais utilizado no mundo, conhecido pela sua simplicidade e flexibilidade. Para integrar a API de CPF da CPFHub.io, você monta uma cadeia de middlewares independentes: um valida o formato do CPF, outro serve o cache, outro chama a API com `fetch` nativo e um último aplica rate limiting local. A API responde em ~900ms e usa autenticação via header `x-api-key` — quando o limite do plano é atingido, ela cobra R$0,15 por consulta excedente sem bloquear a requisição.

---

## 1. Pré-requisitos

* **Node.js 18+** instalado (para suporte nativo a fetch).

* **Express.js** instalado (`npm install express`).

* Uma conta na [**CPFHub.io**](https://www.cpfhub.io/)

---

## 2. Estrutura do projeto

```
cpf-validator/
 ├── middlewares/
 │ ├── validateCpfFormat.js
 │ ├── cpfLookup.js
 │ ├── cpfCache.js
 │ └── rateLimiter.js
 ├── app.js
 ├── package.json
 └── .env
```

---

## 3. Variáveis de ambiente

Crie o arquivo `.env`:

```
CPFHUB_API_KEY=SUA_CHAVE_DE_API
CPFHUB_BASE_URL=https://api.cpfhub.io
CPFHUB_TIMEOUT=5000
PORT=3000
```

Instale o `dotenv`:

```bash
npm install express dotenv
```

---

## 4. Middleware de validação de formato

O primeiro middleware válida se o CPF tem o formato correto antes de prosseguir:

```javascript
// middlewares/validateCpfFormat.js

function validateCpfFormat(req, res, next) {
 const cpf = req.params.cpf?.replace(/\D/g, '');

 if (!cpf || cpf.length !== 11) {
 return res.status(400).json({
 error: 'CPF deve conter exatamente 11 dígitos numéricos'
 });
 }

 // Rejeitar CPFs com todos os dígitos iguais
 if (/^(\d)\1{10}$/.test(cpf)) {
 return res.status(400).json({
 error: 'CPF inválido'
 });
 }

 req.cpf = cpf;
 next();
}

module.exports = validateCpfFormat;
```

---

## 5. Middleware de consulta à API

O segundo middleware consulta a API da CPFHub.io e anexa o resultado ao objeto de request:

```javascript
// middlewares/cpfLookup.js

async function cpfLookup(req, res, next) {
 const cpf = req.cpf;
 const apiKey = process.env.CPFHUB_API_KEY;
 const baseUrl = process.env.CPFHUB_BASE_URL;
 const timeout = parseInt(process.env.CPFHUB_TIMEOUT || '5000', 10);

 const controller = new AbortController();
 const timeoutId = setTimeout(() => controller.abort(), timeout);

 try {
 const response = await fetch(`${baseUrl}/cpf/${cpf}`, {
 method: 'GET',
 headers: {
 'x-api-key': apiKey,
 'Accept': 'application/json'
 },
 signal: controller.signal
 });

 clearTimeout(timeoutId);

 if (!response.ok) {
 const mensagens = {
 400: 'CPF com formato inválido',
 401: 'Chave de API inválida ou ausente',
 404: 'CPF não encontrado'
 };

 return res.status(response.status).json({
 error: mensagens[response.status] || `Erro HTTP ${response.status}`
 });
 }

 const data = await response.json();
 req.cpfData = data;
 next();
 } catch (error) {
 clearTimeout(timeoutId);

 if (error.name === 'AbortError') {
 return res.status(504).json({ error: 'Timeout na consulta de CPF' });
 }

 return res.status(502).json({ error: 'Falha na conexão com a API de CPF' });
 }
}

module.exports = cpfLookup;
```

---

## 6. Middleware de cache

Para evitar consultas duplicadas e economizar requisições do plano:

```javascript
// middlewares/cpfCache.js

const cache = new Map();
const CACHE_TTL = 60 * 60 * 1000; // 1 hora em milissegundos

function cpfCache(req, res, next) {
 const cpf = req.cpf;
 const cached = cache.get(cpf);

 if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
 return res.json(cached.data);
 }

 // Interceptar a resposta para salvar no cache
 const originalJson = res.json.bind(res);
 res.json = function (data) {
 if (res.statusCode === 200 && data.success) {
 cache.set(cpf, { data, timestamp: Date.now() });
 }
 return originalJson(data);
 };

 next();
}

// Limpar entradas expiradas periodicamente
setInterval(() => {
 const now = Date.now();
 for (const [key, value] of cache.entries()) {
 if (now - value.timestamp > CACHE_TTL) {
 cache.delete(key);
 }
 }
}, 5 * 60 * 1000); // A cada 5 minutos

module.exports = cpfCache;
```

---

## 7. Middleware de rate limiting

```javascript
// middlewares/rateLimiter.js

const requests = new Map();

function rateLimiter(windowMs = 60000, maxRequests = 30) {
 return function (req, res, next) {
 const ip = req.ip;
 const now = Date.now();
 const entry = requests.get(ip);

 if (entry && now - entry.timestamp < windowMs) {
 if (entry.count >= maxRequests) {
 return res.status(429).json({
 error: 'Limite de requisições excedido. Tente novamente em breve.'
 });
 }
 entry.count++;
 } else {
 requests.set(ip, { count: 1, timestamp: now });
 }

 next();
 };
}

module.exports = rateLimiter;
```

---

## 8. Aplicação completa

```javascript
// app.js
require('dotenv').config();
const express = require('express');
const validateCpfFormat = require('./middlewares/validateCpfFormat');
const cpfCache = require('./middlewares/cpfCache');
const cpfLookup = require('./middlewares/cpfLookup');
const rateLimiter = require('./middlewares/rateLimiter');

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware global de rate limiting
app.use('/api', rateLimiter(60000, 30));

// Rota de consulta de CPF com pipeline de middlewares
app.get(
 '/api/cpf/:cpf',
 validateCpfFormat,
 cpfCache,
 cpfLookup,
 (req, res) => {
 res.json(req.cpfData);
 }
);

// Health check
app.get('/health', (req, res) => {
 res.json({ status: 'ok' });
});

app.listen(PORT, () => {
 console.log(`Servidor rodando na porta ${PORT}`);
});
```

A cadeia de middlewares executa na ordem: rate limiting, validação de formato, cache, consulta à API, resposta.

---

## 9. Teste com cURL

```bash
node app.js
```

```bash
curl -X GET http://localhost:3000/api/cpf/12345678900 \
 -H "Accept: application/json"
```

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
 }
}
```

Na segunda chamada com o mesmo CPF, a resposta vem do cache sem consultar a API novamente.

---

## 10. Boas práticas

* **Pipeline de middlewares** — Decomponha a lógica em middlewares independentes: validação, cache, consulta e resposta. Isso facilita testes e reutilização.

* **Timeout** — O middleware de lookup usa `AbortController` com 5 segundos para evitar conexões penduradas. A API da CPFHub.io responde em ~900ms, então 5s é uma margem confortável.

* **Cache** — O middleware de cache evita consultas duplicadas e economiza requisições do plano.

* **Variáveis de ambiente** — Use `dotenv` para gerenciar a chave de API. Nunca hardcode no código.

* **Rate limit local** — Proteja seu endpoint de abusos com rate limiting no lado do servidor. A documentação do [Express.js](https://expressjs.com/en/guide/using-middleware.html) detalha como compor middlewares para esse fim.

* **Testes** — Teste cada middleware isoladamente com mocks de `req`, `res` e `next`.

---

## Perguntas frequentes

### O que é um middleware customizado no Express.js e por que usá-lo para validação de CPF?

Um middleware no Express.js é uma função que intercepta a requisição antes de ela chegar ao handler final, podendo modificar o `req`, o `res` ou chamar `next()` para continuar o pipeline. Para validação de CPF, essa abordagem separa responsabilidades: um middleware valida o formato, outro consulta o cache, outro chama a API — tornando cada peça testável de forma independente.

### Como o pipeline de middlewares afeta a performance da consulta de CPF?

A maior parte da latência vem da chamada externa à API, que responde em ~900ms. O middleware de cache é o ponto mais impactante: numa segunda consulta ao mesmo CPF dentro da janela de 1 hora, a resposta sai em menos de 1ms, sem trafegar pela rede. O middleware de validação de formato tem custo praticamente zero — ele só executa regex sobre uma string de 11 dígitos.

### A API CPFHub.io bloqueia requisições quando o limite do plano é atingido?

Não. A API não bloqueia quando o limite mensal é atingido — o comportamento é cobrar R$0,15 por consulta excedente automaticamente. O plano gratuito oferece 50 consultas/mês e o Pro inclui 1.000 consultas por R$149/mês. Implementar cache e rate limiting local reduz o consumo desnecessário de cota.

### Como proteger a chave de API ao fazer deploy do servidor Express.js?

Nunca inclua a chave de API no código-fonte nem no repositório git. Use variáveis de ambiente injetadas pela plataforma de deploy (Railway, Render, Heroku, etc.) e carregue-as com `dotenv` apenas em desenvolvimento local. Em produção, configure diretamente nas variáveis de ambiente do servidor — jamais num `.env` commitado.

---

### 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)
- [Como consumir APIs REST de CPF em Node.js com Axios e Fetch](https://cpfhub.io/blog/como-consumir-apis-rest-de-cpf-em-nodejs-com-axios-e-fetch)
- [Como criar um middleware de consulta de CPF em API Node.js](https://cpfhub.io/blog/como-criar-middleware-consulta-cpf-api-nodejs)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)

---

## Conclusão

O Express.js com middlewares customizados oferece uma integração modular e flexível com a API da [**CPFHub.io**](https://www.cpfhub.io/)

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/)

