# Como validar CPF em aplicações Nuxt.js com server middleware

> Aprenda a integrar a validação de CPF via API em aplicações Nuxt.js usando server middleware para proteger sua chave de API no back-end.

**Publicado:** 24/08/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-validar-cpf-em-aplicacoes-nuxtjs-com-server-middleware

---


Para validar CPF em aplicações Nuxt.js sem expor a chave de API no cliente, crie uma server route em `server/api/cpf/[cpf].ts` que recebe o CPF do front-end, faz a chamada à API CPFHub.io com o header `x-api-key` a partir de uma variável de ambiente e devolve o resultado ao navegador. Dessa forma, o segredo nunca aparece no bundle JavaScript enviado ao usuário.

## Introdução

O Nuxt.js é um dos frameworks mais populares para construção de aplicações Vue.js com renderização server-side (SSR) e geração estática. Quando se trata de integrar APIs externas que exigem autenticação, como a API de consulta de CPF, é fundamental que a chave de API nunca seja exposta no lado do cliente.

A abordagem recomendada em Nuxt.js é utilizar **server middleware** (Nuxt 3) ou **server routes** para criar um proxy que faz a chamada à API no lado do servidor.

---

## Por que usar server middleware para consultas de CPF

A chave de API (x-api-key) é um segredo que não deve ser incluído em código JavaScript enviado ao navegador. Se exposta, qualquer pessoa poderia utilizá-la para consumir sua cota de consultas.

O server middleware do Nuxt.js resolve esse problema criando uma rota no servidor que atua como intermediária entre o front-end e a API externa. O fluxo funciona assim:

1. O front-end faz uma requisição para uma rota interna do Nuxt (por exemplo, `/api/cpf/12345678900`).
2. O server middleware recebe essa requisição e faz a chamada à API da CPFHub.io com a chave de API armazenada no ambiente do servidor.
3. O resultado é devolvido ao front-end sem que a chave de API seja exposta.

---

## Configuração do projeto

### Estrutura de diretórios (Nuxt 3)

```
meu-projeto/
 server/
 api/
 cpf/
 [cpf].ts
 pages/
 index.vue
 .env
 nuxt.config.ts
```

### Variáveis de ambiente

Crie um arquivo `.env` na raiz do projeto:

```
CPFHUB_API_KEY=SUA_CHAVE_DE_API
```

No `nuxt.config.ts`, configure o acesso à variável de ambiente:

```typescript
export default defineNuxtConfig({
 runtimeConfig: {
 cpfhubApiKey: process.env.CPFHUB_API_KEY || ''
 }
})
```

A propriedade `runtimeConfig` sem o prefixo `public` garante que a variável esteja disponível apenas no lado do servidor.

---

## Criando a server route

Crie o arquivo `server/api/cpf/[cpf].ts`:

```typescript
import { defineEventHandler, createError } from 'h3'

export default defineEventHandler(async (event) => {
 const cpf = event.context.params?.cpf

 if (!cpf || cpf.length !== 11 || !/^\d{11}$/.test(cpf)) {
 throw createError({
 statusCode: 400,
 statusMessage: 'CPF inválido. Informe 11 dígitos numéricos.'
 })
 }

 const config = useRuntimeConfig()
 const apiKey = config.cpfhubApiKey

 if (!apiKey) {
 throw createError({
 statusCode: 500,
 statusMessage: 'Chave de API não configurada no servidor.'
 })
 }

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

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

 clearTimeout(timeoutId)

 if (!response.ok) {
 if (response.status === 429) {
 throw createError({
 statusCode: 429,
 statusMessage: 'Limite de consultas atingido. Tente novamente mais tarde.'
 })
 }
 throw createError({
 statusCode: response.status,
 statusMessage: `Erro na API: ${response.statusText}`
 })
 }

 const dados = await response.json()
 return dados
 } catch (error: any) {
 clearTimeout(timeoutId)

 if (error.name === 'AbortError') {
 throw createError({
 statusCode: 504,
 statusMessage: 'Tempo limite excedido na consulta de CPF.'
 })
 }

 if (error.statusCode) {
 throw error
 }

 throw createError({
 statusCode: 500,
 statusMessage: 'Erro interno ao consultar CPF.'
 })
 }
})
```

Essa rota está acessível em `http://localhost:3000/api/cpf/{cpf}` durante o desenvolvimento e será automaticamente incluída no build de produção.

---

## Consumindo a rota no front-end

Crie um componente Vue que permite ao usuário digitar um CPF e consultar os dados.

### Página de consulta (pages/index.vue)

```vue
<template>
 <div class="container">
 <h1>Consulta de CPF</h1>
 <form @submit.prevent="consultarCpf">
 <input
 v-model="cpfInput"
 type="text"
 placeholder="Digite o CPF (somente números)"
 maxlength="11"
 />
 <button type="submit" :disabled="carregando">
 {{ carregando ? 'Consultando...' : 'Consultar' }}
 </button>
 </form>

 <div v-if="resultado" class="resultado">
 <p><strong>Nome:</strong> {{ resultado.data.name }}</p>
 <p><strong>CPF:</strong> {{ resultado.data.cpf }}</p>
 <p><strong>Data de nascimento:</strong> {{ resultado.data.birthDate }}</p>
 <p><strong>Gênero:</strong> {{ resultado.data.gender }}</p>
 </div>

 <div v-if="erro" class="erro">
 <p>{{ erro }}</p>
 </div>
 </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const cpfInput = ref('')
const resultado = ref(null)
const erro = ref('')
const carregando = ref(false)

async function consultarCpf() {
 erro.value = ''
 resultado.value = null
 carregando.value = true

 const cpf = cpfInput.value.replace(/\D/g, '')

 if (cpf.length !== 11) {
 erro.value = 'Informe um CPF com 11 dígitos.'
 carregando.value = false
 return
 }

 try {
 const dados = await $fetch(`/api/cpf/${cpf}`)
 resultado.value = dados
 } catch (e: any) {
 erro.value = e.data?.message || 'Erro ao consultar CPF.'
 } finally {
 carregando.value = false
 }
}
</script>
```

---

## Testando com cURL

Você pode testar a server route diretamente via cURL durante o desenvolvimento:

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

A resposta será o JSON retornado pela API da CPFHub.io, sem que a chave de API seja visível para o cliente.

---

## Adicionando validação sintática no server middleware

Para evitar consultas desnecessárias à API, implemente a validação dos dígitos verificadores do CPF no próprio server middleware:

```typescript
function validarDigitosCpf(cpf: string): boolean {
 if (cpf.length !== 11) return false
 if (/^(\d)\1{10}$/.test(cpf)) return false

 let soma = 0
 for (let i = 0; i < 9; i++) {
 soma += parseInt(cpf.charAt(i)) * (10 - i)
 }
 let resto = (soma * 10) % 11
 if (resto === 10) resto = 0
 if (resto !== parseInt(cpf.charAt(9))) return false

 soma = 0
 for (let i = 0; i < 10; i++) {
 soma += parseInt(cpf.charAt(i)) * (11 - i)
 }
 resto = (soma * 10) % 11
 if (resto === 10) resto = 0
 if (resto !== parseInt(cpf.charAt(10))) return false

 return true
}
```

Adicione essa verificação antes da chamada à API para rejeitar CPFs sintaticamente inválidos sem consumir uma consulta.

---

## Boas práticas

* **Nunca exponha a chave de API** -- Utilize `runtimeConfig` sem o prefixo `public` para manter segredos no servidor.

* **Timeout** -- Sempre inclua timeout nas requisições para evitar que o servidor fique travado.

* **Validação no front-end** -- Valide o formato do CPF (11 dígitos numéricos) antes de enviar ao servidor.

* **Validação no back-end** -- Revalide no server middleware, pois o front-end pode ser contornado.

* **Rate limit** -- No plano gratuito da CPFHub.io, o limite é de 1 requisição a cada 2 segundos, com 50 consultas/mês. O plano Pro oferece 1 requisição por segundo e 1.000 consultas/mês por R$ 149.

---

## Perguntas frequentes

### Por que usar server routes em vez de chamar a API diretamente do componente Vue?
Chamar a API CPFHub.io diretamente do componente Vue expõe a `x-api-key` no bundle JavaScript do navegador, onde qualquer usuário pode inspecioná-la. Com a server route, a chave fica em variável de ambiente no servidor e nunca trafega até o cliente — essa é a abordagem recomendada pelo [OWASP](https://owasp.org/www-project-top-ten/) para proteção de segredos em aplicações web.

### Como o Nuxt.js lida com o runtimeConfig em produção?
Em produção, o `runtimeConfig` é preenchido pelas variáveis de ambiente do servidor no momento do deploy — no Vercel, Render ou qualquer outro provedor, você define `CPFHUB_API_KEY` nas configurações de environment. Os valores sem o prefixo `public` ficam acessíveis apenas em `server/` e nunca são injetados no bundle do cliente.

### O que acontece se a consulta de CPF exceder o limite do plano gratuito?
A API CPFHub.io não retorna erro bloqueante ao atingir o limite de 50 consultas mensais. Em vez disso, cada consulta adicional é cobrada a R$0,15. No server middleware, o status HTTP retornado será 200 normalmente — acompanhe o consumo no dashboard em `app.cpfhub.io` para evitar cobranças inesperadas.

### Como adicionar cache nas server routes do Nuxt para economizar consultas?
Use o composable `useStorage` do Nitro (camada de servidor do Nuxt 3) para armazenar resultados em memória ou Redis. Defina um TTL adequado — por exemplo, 24 horas para dados cadastrais que raramente mudam — e verifique o cache antes de chamar a API. Isso reduz o consumo de consultas e a latência percebida pelo usuário.

### 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)
- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](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)
- [10 erros mais comuns ao integrar uma API de CPF e como evitá-los](https://cpfhub.io/blog/10-erros-mais-comuns-ao-integrar-uma-api-de-cpf)

---

## Conclusão

Integrar a validação de CPF em aplicações Nuxt.js com server middleware é a abordagem mais segura e eficiente para proteger sua chave de API e garantir que as consultas sejam feitas de forma controlada. Com a API da [**CPFHub.io**](https://www.cpfhub.io/), o retorno inclui nome, gênero e data de nascimento do titular em uma única requisição GET.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e implemente hoje mesmo a server route de validação de CPF na sua aplicação Nuxt.js.

