# Como Criar uma Camada de Abstração para Trocar de Provedor de API de CPF Facilmente

> Aprenda a criar uma camada de abstração que permite trocar de provedor de API de CPF sem alterar o código da aplicação. Padrões Strategy e Adapter.

**Publicado:** 25/02/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/camada-abstracao-provedor-api-cpf

---


## Introdução

Acoplar sua aplicação diretamente a um provedor de API de CPF é um risco técnico significativo. Se o provedor mudar sua interface, aumentar preços ou sair do mercado, você precisará alterar código em dezenas de pontos da aplicação. A solução é criar uma **camada de abstração** que isole sua lógica de negócio dos detalhes de implementação do provedor.

## Por que abstrair o provedor de API

Sem abstração, cada chamada à API fica espalhada pelo código, criando um acoplamento forte que dificulta qualquer mudança futura.

| Cenário | Sem abstração | Com abstração |
|---------|--------------|--------------|
| Trocar de provedor | Alterar N arquivos | Alterar 1 adaptador |
| Adicionar cache | Modificar cada chamada | Adicionar decorator |
| Testes unitários | Mock complexo | Interface simples |
| Múltiplos provedores | Código duplicado | Configuração |
| Mudança de contrato | Refatoração massiva | Ajuste no adapter |

- **Princípio da Inversão de Dependência** -- módulos de alto nível não devem depender de módulos de baixo nível, ambos devem depender de abstrações
- **Princípio Aberto/Fechado** -- o sistema deve ser aberto para extensão (novos provedores) e fechado para modificação
- **Testabilidade** -- com uma interface definida, criar mocks para testes se torna trivial

---

## Definindo a interface do contrato

O primeiro passo é definir um contrato que todos os provedores devem implementar. Isso garante que sua aplicação sempre receba dados no mesmo formato, independentemente da origem.

```javascript
// contracts/cpf-provider.js
class CpfProviderInterface {
 /**
 * @param {string} cpf - CPF sem formatação
 * @returns {Promise<CpfResult>}
 */
 async consultar(cpf) {
 throw new Error("Método consultar() deve ser implementado");
 }
}

// Formato padronizado de resposta
class CpfResult {
 constructor({ cpf, nome, genero, dataNascimento, valido }) {
 this.cpf = cpf;
 this.nome = nome;
 this.genero = genero;
 this.dataNascimento = dataNascimento;
 this.valido = valido;
 }
}

module.exports = { CpfProviderInterface, CpfResult };
```

- **CpfResult** -- objeto de valor que padroniza a resposta independentemente do provedor
- **CpfProviderInterface** -- contrato que força cada adaptador a implementar o método `consultar()`
- **Desacoplamento** -- sua aplicação conhece apenas `CpfResult`, nunca o formato raw da API

---

## Implementando adaptadores por provedor

Cada provedor recebe seu próprio adaptador que traduz a resposta para o formato padronizado.

```javascript
// adapters/cpfhub-adapter.js
const axios = require("axios");
const { CpfProviderInterface, CpfResult } = require("../contracts/cpf-provider");

class CpfHubAdapter extends CpfProviderInterface {
 constructor(apiKey) {
 super();
 this.apiKey = apiKey;
 this.baseUrl = "https://api.cpfhub.io";
 }

 async consultar(cpf) {
 const response = await axios.get(`${this.baseUrl}/cpf/${cpf}`, {
 headers: { "x-api-key": this.apiKey },
 timeout: 10000,
 });

 const { data } = response.data;
 return new CpfResult({
 cpf: data.cpf,
 nome: data.name,
 genero: data.gender,
 dataNascimento: data.birthDate,
 valido: response.data.success,
 });
 }
}

// adapters/provedor-alternativo-adapter.js
class ProvedorAlternativoAdapter extends CpfProviderInterface {
 constructor(token) {
 super();
 this.token = token;
 }

 async consultar(cpf) {
 const response = await axios.post("https://outro-provedor.com/api/v2/cpf", {
 documento: cpf,
 }, {
 headers: { Authorization: `Bearer ${this.token}` },
 });

 return new CpfResult({
 cpf: response.data.documento,
 nome: response.data.nome_completo,
 genero: response.data.sexo === "M" ? "male" : "female",
 dataNascimento: response.data.dt_nascimento,
 valido: response.data.status === "ativo",
 });
 }
}

module.exports = { CpfHubAdapter, ProvedorAlternativoAdapter };
```

- **Tradução de formato** -- cada adapter mapeia os campos específicos do provedor para o formato padrão
- **Encapsulamento** -- detalhes como headers de autenticação e URLs ficam isolados no adaptador
- **Extensibilidade** -- adicionar um novo provedor significa apenas criar um novo adaptador

---

## Criando a factory e o serviço

A factory cria o adaptador correto baseado na configuração, e o serviço expõe uma API limpa para o resto da aplicação.

```javascript
// factory/cpf-provider-factory.js
const { CpfHubAdapter, ProvedorAlternativoAdapter } = require("../adapters");

function criarProvedor(config) {
 const provedores = {
 cpfhub: () => new CpfHubAdapter(config.CPFHUB_API_KEY),
 alternativo: () => new ProvedorAlternativoAdapter(config.ALT_TOKEN),
 };

 const factory = provedores[config.CPF_PROVIDER];
 if (!factory) {
 throw new Error(`Provedor desconhecido: ${config.CPF_PROVIDER}`);
 }
 return factory();
}

// services/cpf-service.js
class CpfService {
 constructor(provider) {
 this.provider = provider;
 }

 async validar(cpf) {
 const cpfLimpo = cpf.replace(/\D/g, "");
 if (cpfLimpo.length !== 11) {
 throw new Error("CPF deve conter 11 dígitos");
 }
 return this.provider.consultar(cpfLimpo);
 }
}

// Uso: trocar provedor é mudar uma variável de ambiente
const provider = criarProvedor(process.env);
const cpfService = new CpfService(provider);

// Em qualquer lugar da aplicação
const resultado = await cpfService.validar("123.456.789-09");
console.log(resultado.nome);
```

| Padrão utilizado | Benefício |
|-----------------|-----------|
| **Adapter** | Traduz interfaces incompatíveis para um formato comum |
| **Factory** | Centraliza a criação de objetos baseada em configuração |
| **Strategy** | Permite trocar algoritmos (provedores) em tempo de execução |
| **Dependency Injection** | O serviço recebe o provedor, não o cria internamente |

---

## Perguntas frequentes

### O que é necessário para implementar validação de CPF neste contexto?
A validação de CPF exige uma chamada à API com o número do documento e a chave de autenticação. A CPFHub.io retorna o status do CPF, nome do titular e data de nascimento em menos de 200ms, permitindo a verificação em tempo real durante o cadastro ou transação.

### A API CPFHub.io funciona para todos os volumes de consulta?
Sim. O plano gratuito oferece 50 consultas por mês sem cartão de crédito — ideal para testes e projetos pequenos. Para volumes maiores, o plano Pro inclui 1.000 consultas mensais por R$149. Se o limite for ultrapassado, a API não bloqueia: cobra R$0,15 por consulta adicional.

### Como garantir conformidade com a LGPD ao usar uma API de CPF?
Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não guarde o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A [ANPD](https://www.gov.br/anpd) orienta que dados de identificação devem ser tratados com o princípio da necessidade.

### Quanto tempo leva para integrar a API CPFHub.io?
A integração básica leva menos de 30 minutos: crie uma conta em cpfhub.io, gere a API key no painel e faça uma chamada GET para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`. A documentação inclui exemplos em Python, Node.js, PHP, Java e outras linguagens.

### Leia também

- [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)
- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [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)
- [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

Criar uma camada de abstração para sua API de CPF é um investimento que se paga rapidamente. Com adaptadores isolados, uma interface padronizada e uma factory configurável, trocar de provedor vira uma mudança de variável de ambiente. Comece implementando o padrão com a API da [cpfhub.io](https://www.cpfhub.io/).

