# Como integrar validação de CPF em aplicações Adonis.js (Node.js)

> Aprenda a integrar a API de consulta de CPF da CPFHub.io em aplicações Adonis.js usando services, validators e controllers.

**Publicado:** 25/05/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-aplicacoes-adonis-js

---

O **Adonis.js** é um framework Node.js completo, inspirado no Laravel, que oferece uma estrutura opinada com ORM, validação, autenticação e injeção de dependência embutidos. Para integrar a API de CPF da CPFHub.io, basta criar um service dedicado que faz um GET para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`, usar o VineJS para validar a entrada e expor um controller com as rotas. A latência média é de ~900ms, então configure o `AbortController` com tempo suficiente — 5 a 10 segundos é adequado para produção.

---

## 1. Pré-requisitos

* **Adonis.js v6** configurado com `npm init adonisjs@latest`.

* Node.js 20+ instalado.

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

---

## 2. Configure as variáveis de ambiente

Adicione as variáveis no arquivo `.env`:

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

Registre a validação no `env.ts`:

```typescript
// start/env.ts
import { Env } from '@adonisjs/core/env'

export default await Env.create(new URL('../', import.meta.url), {
 // ... outras variáveis
 CPFHUB_API_KEY: Env.schema.string(),
 CPFHUB_BASE_URL: Env.schema.string({ format: 'url' }),
 CPFHUB_TIMEOUT: Env.schema.number(),
})
```

---

## 3. Crie o service de consulta

Crie o serviço em `app/services/cpfhub_service.ts`:

```typescript
// app/services/cpfhub_service.ts
import env from '#start/env'

export interface CpfData {
 cpf: string
 name: string
 nameUpper: string
 gender: string
 birthDate: string
 day: number
 month: number
 year: number
}

export interface CpfResponse {
 success: boolean
 data: CpfData
}

export default class CpfHubService {
 private baseUrl: string
 private apiKey: string
 private timeout: number

 constructor() {
 this.baseUrl = env.get('CPFHUB_BASE_URL')
 this.apiKey = env.get('CPFHUB_API_KEY')
 this.timeout = env.get('CPFHUB_TIMEOUT')
 }

 async consultarCpf(cpf: string): Promise<CpfResponse> {
 const cpfLimpo = cpf.replace(/\D/g, '')

 if (cpfLimpo.length !== 11) {
 throw new Error('CPF deve conter 11 dígitos')
 }

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

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

 clearTimeout(timeoutId)

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

 throw new Error(mensagens[response.status] || `Erro HTTP ${response.status}`)
 }

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

---

## 4. Crie o validator

O Adonis.js tem um sistema de validação robusto. Crie um validator para o CPF:

```typescript
// app/validators/cpf_validator.ts
import vine from '@vinejs/vine'

export const cpfValidator = vine.compile(
 vine.object({
 cpf: vine
 .string()
 .trim()
 .regex(/^\d{11}$/)
 .fixedLength(11),
 })
)
```

---

## 5. Crie o controller

```typescript
// app/controllers/cpf_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
import CpfHubService from '#services/cpfhub_service'
import { cpfValidator } from '#validators/cpf_validator'

export default class CpfController {
 private cpfHubService: CpfHubService

 constructor() {
 this.cpfHubService = new CpfHubService()
 }

 async show({ params, response }: HttpContext) {
 const cpf = params.cpf.replace(/\D/g, '')

 try {
 await cpfValidator.validate({ cpf })
 } catch {
 return response.badRequest({ error: 'CPF deve conter exatamente 11 dígitos numéricos' })
 }

 try {
 const resultado = await this.cpfHubService.consultarCpf(cpf)
 return response.ok(resultado)
 } catch (error) {
 if (error instanceof Error) {
 return response.badRequest({ error: error.message })
 }
 return response.internalServerError({ error: 'Erro interno' })
 }
 }

 async validate({ request, response }: HttpContext) {
 const payload = await request.validateUsing(cpfValidator)

 try {
 const resultado = await this.cpfHubService.consultarCpf(payload.cpf)

 if (resultado.success) {
 return response.ok({
 valid: true,
 name: resultado.data.name,
 birthDate: resultado.data.birthDate,
 gender: resultado.data.gender,
 })
 }

 return response.ok({ valid: false })
 } catch (error) {
 return response.badGateway({
 error: error instanceof Error ? error.message : 'Falha na validação',
 })
 }
 }
}
```

---

## 6. Registre as rotas

```typescript
// start/routes.ts
import router from '@adonisjs/core/services/router'

const CpfController = () => import('#controllers/cpf_controller')

router.get('/api/cpf/:cpf', [CpfController, 'show'])
router.post('/api/cpf/validate', [CpfController, 'validate'])
```

---

## 7. Teste com cURL

Inicie o servidor e teste:

```bash
node ace serve --watch
```

```bash
curl -X GET http://localhost:3333/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
 }
}
```

---

## 8. Middleware de rate limiting

Crie um middleware para limitar consultas por IP:

```typescript
// app/middleware/rate_limit_middleware.ts
import type { HttpContext } from '@adonisjs/core/http'
import type { NextFn } from '@adonisjs/core/types/http'

const requests = new Map<string, { count: number; timestamp: number }>()

export default class RateLimitMiddleware {
 async handle({ request, response }: HttpContext, next: NextFn) {
 const ip = request.ip()
 const now = Date.now()
 const windowMs = 60000 // 1 minuto
 const maxRequests = 30

 const entry = requests.get(ip)

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

 return next()
 }
}
```

---

## 9. Boas práticas

* **Validação de env** -- O Adonis.js valida variáveis de ambiente na inicialização. Se `CPFHUB_API_KEY` estiver ausente, a aplicação não sobe.

* **Timeout** -- Configure o `AbortController` com pelo menos 5 segundos para acomodar a latência média de ~900ms da API com margem de segurança.

* **Validators** -- Use o VineJS (validador nativo do Adonis) para validar dados de entrada antes de chamar a API.

* **Services** -- Centralize a lógica de integração em services para facilitar testes e manutenção.

* **Planos** -- O plano gratuito da CPFHub.io inclui 50 consultas/mês. Quando o limite é atingido, a API não bloqueia: cobra R$0,15 por consulta extra. Para produção, o plano Pro (R$149/mês) inclui 1.000 consultas.

A [documentação oficial do Adonis.js](https://docs.adonisjs.com) cobre o sistema de providers, validators e serviços em detalhe.

---

## Perguntas frequentes

### Como integrar a API de CPF em um projeto Adonis.js existente?

Crie um service em `app/services/cpfhub_service.ts` com o método `consultarCpf`, registre as variáveis de ambiente no `env.ts` e injete o service no controller. O Adonis.js valida as variáveis de ambiente na inicialização, então a aplicação não sobe se `CPFHUB_API_KEY` estiver ausente — o que previne erros silenciosos em produção.

### Qual timeout configurar para a API da CPFHub.io no Adonis.js?

A latência média da API é de ~900ms. Configure o `AbortController` com pelo menos 5.000ms (5 segundos) para ter margem adequada em condições de rede variável. Em ambientes com alta carga, considere 8 a 10 segundos para evitar cancelamentos prematuros que gerariam falsos negativos na validação.

### A API retorna erro 429 quando o limite de consultas é atingido?

Não. A CPFHub.io não bloqueia requisições ao atingir o limite do plano. Quando o limite mensal é excedido, cada consulta adicional é cobrada automaticamente a R$0,15. Por isso, implementar um middleware de rate limiting na aplicação Adonis.js é uma boa prática para controlar o volume e evitar cobranças inesperadas.

### Como testar o service de CPF no Adonis.js sem consumir consultas reais?

Use a injeção de dependência do Adonis.js para criar um mock do `CpfHubService` nos testes. O framework suporta substituição de bindings no container de IoC, o que permite simular respostas da API sem fazer chamadas reais — preservando as consultas do plano para o ambiente de produção.

### 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 API de CPF em TypeScript com tipagem segura](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-typescript-com-tipagem-segura)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)
- [Autenticação em APIs REST: como garantir segurança na consulta de CPF](https://cpfhub.io/blog/autenticacao-apis-rest-seguranca-consulta-cpf)

---

## Conclusão

O Adonis.js oferece uma estrutura organizada e produtiva para integrar a API da [**CPFHub.io**](https://www.cpfhub.io/)

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

