# Como consumir API de CPF em Fastify com plugins e decorators

> Aprenda a consumir a API de consulta de CPF da CPFHub.io em Fastify usando plugins, decorators e schemas para validação de alto desempenho.

**Publicado:** 09/06/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-consumir-api-de-cpf-em-fastify-com-plugins-e-decorators

---


O [Fastify](https://fastify.dev) é um dos frameworks Node.js mais rápidos disponíveis, projetado para alto desempenho com baixo overhead. Sua arquitetura baseada em **plugins** e **decorators** permite encapsular a integração com a API de CPF de forma modular e reutilizável. Com schemas JSON integrados, o Fastify valida parâmetros de entrada e serializa respostas automaticamente, sem configuração extra.

---

## 1. Pré-requisitos

* **Node.js 18+** instalado.

* **Fastify** instalado (`npm install fastify`).

* Pacotes adicionais: `@fastify/env`, `@fastify/rate-limit`.

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

---

## 2. Instale as dependências

```bash
npm init -y
npm install fastify @fastify/env @fastify/rate-limit
```

---

## 3. Configure as 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
```

---

## 4. Plugin de integração com a CPFHub.io

O plugin encapsula toda a lógica de integração e expõe um decorator na instância do Fastify:

```javascript
// plugins/cpfhub.js
const fp = require('fastify-plugin');

async function cpfhubPlugin(fastify, options) {
 const { apiKey, baseUrl, timeout } = options;

 async function consultarCpf(cpf) {
 const cpfLimpo = cpf.replace(/\D/g, '');

 if (cpfLimpo.length !== 11) {
 throw fastify.httpErrors.badRequest('CPF deve conter 11 dígitos');
 }

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

 try {
 const response = await fetch(`${baseUrl}/cpf/${cpfLimpo}`, {
 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'
 };

 const msg = mensagens[response.status] || `Erro HTTP ${response.status}`;

 if (response.status === 401) throw fastify.httpErrors.unauthorized(msg);
 if (response.status === 404) throw fastify.httpErrors.notFound(msg);
 throw fastify.httpErrors.badRequest(msg);
 }

 return await response.json();
 } catch (error) {
 clearTimeout(timeoutId);

 if (error.statusCode) throw error; // Já é um httpError

 if (error.name === 'AbortError') {
 throw fastify.httpErrors.gatewayTimeout('Timeout na consulta de CPF');
 }

 throw fastify.httpErrors.badGateway('Falha na conexão com a API de CPF');
 }
 }

 // Decorator: disponibiliza cpfhub.consultarCpf em todas as rotas
 fastify.decorate('cpfhub', { consultarCpf });
}

module.exports = fp(cpfhubPlugin, {
 name: 'cpfhub',
 dependencies: ['@fastify/sensible']
});
```

O uso de `fastify-plugin` (`fp`) garante que o decorator seja acessível em todo o escopo da aplicação, não apenas no contexto do plugin.

---

## 5. Schemas de validação e serialização

Defina schemas JSON para validar parâmetros de entrada e serializar a resposta:

```javascript
// schemas/cpf.js
const cpfParamsSchema = {
 type: 'object',
 required: ['cpf'],
 properties: {
 cpf: {
 type: 'string',
 pattern: '^\\d{11}$',
 description: 'CPF com 11 dígitos numéricos'
 }
 }
};

const cpfResponseSchema = {
 type: 'object',
 properties: {
 success: { type: 'boolean' },
 data: {
 type: 'object',
 properties: {
 cpf: { type: 'string' },
 name: { type: 'string' },
 nameUpper: { type: 'string' },
 gender: { type: 'string' },
 birthDate: { type: 'string' },
 day: { type: 'integer' },
 month: { type: 'integer' },
 year: { type: 'integer' }
 }
 }
 }
};

module.exports = { cpfParamsSchema, cpfResponseSchema };
```

---

## 6. Aplicação completa

```javascript
// app.js
require('dotenv').config();
const fastify = require('fastify')({
 logger: true
});

const { cpfParamsSchema, cpfResponseSchema } = require('./schemas/cpf');

async function build() {
 // Plugins essenciais
 await fastify.register(require('@fastify/sensible'));

 // Rate limiting
 await fastify.register(require('@fastify/rate-limit'), {
 max: 30,
 timeWindow: '1 minute'
 });

 // Plugin CPFHub
 await fastify.register(require('./plugins/cpfhub'), {
 apiKey: process.env.CPFHUB_API_KEY,
 baseUrl: process.env.CPFHUB_BASE_URL,
 timeout: parseInt(process.env.CPFHUB_TIMEOUT || '5000', 10)
 });

 // Rota de consulta de CPF
 fastify.get('/api/cpf/:cpf', {
 schema: {
 params: cpfParamsSchema,
 response: {
 200: cpfResponseSchema
 }
 }
 }, async (request, reply) => {
 const { cpf } = request.params;
 const resultado = await fastify.cpfhub.consultarCpf(cpf);
 return resultado;
 });

 // Health check
 fastify.get('/health', async () => {
 return { status: 'ok' };
 });

 return fastify;
}

build().then((app) => {
 app.listen({ port: parseInt(process.env.PORT || '3000', 10), host: '0.0.0.0' }, (err) => {
 if (err) {
 app.log.error(err);
 process.exit(1);
 }
 });
});
```

---

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

Se o CPF não tiver 11 dígitos, o schema de validação retorna automaticamente um erro 400 antes de executar o handler.

---

## 8. Plugin de cache

Crie um plugin de cache para evitar consultas repetidas:

```javascript
// plugins/cpfCache.js
const fp = require('fastify-plugin');

async function cpfCachePlugin(fastify, options) {
 const cache = new Map();
 const ttl = options.ttl || 3600000; // 1 hora padrão

 fastify.decorate('cpfCache', {
 get(cpf) {
 const entry = cache.get(cpf);
 if (entry && Date.now() - entry.timestamp < ttl) {
 return entry.data;
 }
 cache.delete(cpf);
 return null;
 },

 set(cpf, data) {
 cache.set(cpf, { data, timestamp: Date.now() });
 }
 });
}

module.exports = fp(cpfCachePlugin, { name: 'cpfCache' });
```

Use na rota:

```javascript
fastify.get('/api/cpf/:cpf', {
 schema: { params: cpfParamsSchema, response: { 200: cpfResponseSchema } }
}, async (request, reply) => {
 const { cpf } = request.params;

 // Verificar cache
 const cached = fastify.cpfCache.get(cpf);
 if (cached) return cached;

 // Consultar API
 const resultado = await fastify.cpfhub.consultarCpf(cpf);

 // Salvar no cache
 if (resultado.success) {
 fastify.cpfCache.set(cpf, resultado);
 }

 return resultado;
});
```

---

## 9. Hook para logging de consultas

Use hooks do Fastify para registrar cada consulta:

```javascript
fastify.addHook('onResponse', (request, reply, done) => {
 if (request.url.startsWith('/api/cpf/')) {
 fastify.log.info({
 cpf: request.params.cpf,
 statusCode: reply.statusCode,
 responseTime: reply.elapsedTime
 }, 'Consulta de CPF registrada');
 }
 done();
});
```

---

## 10. Boas práticas

* **Plugins** -- Encapsule a integração com a CPFHub.io em um plugin reutilizável. O padrão de plugin do Fastify facilita testes e compartilhamento.

* **Decorators** -- Exponha a função de consulta como decorator para acesso em qualquer rota sem imports manuais.

* **Schemas** -- Use JSON Schema para validar parâmetros de entrada e serializar respostas automaticamente. O Fastify usa os schemas para otimizar a serialização.

* **Timeout** -- O `AbortController` com 5 segundos é configurado no plugin e evita consultas pendentes.

* **Rate limit local** -- O `@fastify/rate-limit` protege o endpoint de abusos internos. A CPFHub.io não bloqueia ao atingir o limite do plano — cobra R$0,15 por consulta adicional (Gratuito: 50/mês, Pro: 1.000/mês por R$149).

* **Sensible** -- O `@fastify/sensible` adiciona helpers como `httpErrors` para tratamento de erros padronizado.

---

## Perguntas frequentes

### Por que usar plugins e decorators em vez de importar a função diretamente nas rotas?
Plugins e decorators seguem o modelo de encapsulamento do Fastify, conforme descrito na [documentação oficial do framework](https://fastify.dev/docs/latest/Reference/Plugins/). A integração fica isolada em um único ponto, o que facilita testes unitários, substituição do provedor de CPF e reuso da lógica em múltiplas rotas sem duplicação de código.

### O @fastify/rate-limit e o rate limit da CPFHub.io são a mesma coisa?
Não. O `@fastify/rate-limit` controla quantas requisições chegam ao seu servidor por minuto — protegendo contra abusos dos seus próprios usuários. Já a CPFHub.io controla quantas consultas sua chave de API realiza por mês. Os dois limites são independentes e complementares.

### Como o plugin lida com timeout na chamada à API de CPF?
O `AbortController` cancela a requisição após o tempo configurado (padrão: 5 segundos). Quando isso acontece, o plugin lança um `gatewayTimeout` (503), informando ao cliente que o serviço externo não respondeu a tempo, sem deixar a conexão pendente no servidor.

### O cache em memória (Map) é suficiente para produção?
Para volumes baixos, sim. Para aplicações com múltiplas instâncias ou alto tráfego, substitua o `Map` por Redis ou Memcached para compartilhar o cache entre processos. O padrão de plugin do Fastify torna essa substituição simples: basta criar um novo plugin que implemente a mesma interface `get`/`set`.

### Leia também

- [Como implementar cache inteligente em respostas de API de CPF](https://cpfhub.io/blog/como-implementar-cache-inteligente-respostas-api-cpf)
- [Como implementar retry e backoff exponencial em consultas de API de CPF](https://cpfhub.io/blog/como-implementar-retry-backoff-exponencial-consultas-api-cpf)
- [SLA de API de CPF: níveis de disponibilidade](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)

---

## Conclusão

O Fastify com plugins e decorators oferece a melhor combinação de performance e organização para consumir a API da [**CPFHub.io**](https://www.cpfhub.io/)

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

