# Como validar CPF em aplicações Angular usando services e interceptors

> Tutorial completo de como integrar validação de CPF via API em aplicações Angular usando services, interceptors e reactive forms.

**Publicado:** 27/03/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-validar-cpf-angular-services-interceptors

---


## Introdução

Angular é um dos frameworks front-end mais utilizados em projetos corporativos no Brasil, especialmente em fintechs, bancos e sistemas de gestão. Em muitos desses projetos, a validação de CPF é um requisito obrigatório -- seja no cadastro de usuários, no checkout de uma loja ou na abertura de conta digital.

Embora a validação dos dígitos verificadores possa ser feita localmente, confirmar que o CPF realmente existe e obter os dados do titular exige uma consulta a uma API externa. A [**CPFHub.io**](https://www.cpfhub.io/) oferece uma API REST simples de integrar em qualquer projeto Angular, com autenticação via header e resposta JSON tipada.

---
## Arquitetura da solução

A integração será organizada em três camadas:

* **Service** -- Encapsula a chamada à API da CPFHub.io e expõe métodos tipados para o resto da aplicação.

* **Interceptor** -- Adiciona automaticamente o header `x-api-key` em todas as requisições para a API, centralizando a autenticação.

* **Componente com Reactive Forms** -- Formulário que coleta o CPF, aciona a validação e exibe os dados retornados.

Essa separação de responsabilidades segue as boas práticas do Angular e facilita testes unitários e manutenção.

---

## Configurando o ambiente

### Variáveis de ambiente

Primeiro, configure a chave de API nas variáveis de ambiente do Angular. Nunca coloque a chave diretamente no código-fonte.

```typescript
// src/environments/environment.ts
export const environment = {
 production: false,
 cpfhubApiUrl: 'https://api.cpfhub.io',
 cpfhubApiKey: 'SUA_CHAVE_DE_API'
};
```

### Importar HttpClientModule

No módulo principal, importe o `HttpClientModule`:

```typescript
// src/app/app.module.ts
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { CpfhubInterceptor } from './interceptors/cpfhub.interceptor';

@NgModule({
 imports: [
 HttpClientModule,
 // ...outros imports
 ],
 providers: [
 {
 provide: HTTP_INTERCEPTORS,
 useClass: CpfhubInterceptor,
 multi: true
 }
 ]
})
export class AppModule {}
```

---

## Criando o interceptor de autenticação

O interceptor adiciona automaticamente os headers necessários em todas as requisições direcionadas à API da CPFHub.io. Isso evita repetição de código e garante que a autenticação nunca seja esquecida.

```typescript
// src/app/interceptors/cpfhub.interceptor.ts
import { Injectable } from '@angular/core';
import {
 HttpInterceptor,
 HttpRequest,
 HttpHandler,
 HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';

@Injectable()
export class CpfhubInterceptor implements HttpInterceptor {
 intercept(
 req: HttpRequest<any>,
 next: HttpHandler
 ): Observable<HttpEvent<any>> {
 if (req.url.startsWith(environment.cpfhubApiUrl)) {
 const authReq = req.clone({
 setHeaders: {
 'x-api-key': environment.cpfhubApiKey,
 'Accept': 'application/json'
 }
 });
 return next.handle(authReq);
 }
 return next.handle(req);
 }
}
```

O interceptor verifica se a URL da requisição pertence à API da CPFHub.io antes de adicionar os headers. Isso garante que a chave de API não seja enviada para outros serviços.

---

## Criando o service de consulta de CPF

O service encapsula toda a lógica de comunicação com a API e expõe interfaces tipadas.

### Definindo as interfaces

```typescript
// src/app/models/cpf-response.model.ts
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;
}
```

### Implementando o service

```typescript
// src/app/services/cpfhub.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';
import { CpfResponse } from '../models/cpf-response.model';
import { environment } from '../../environments/environment';

@Injectable({
 providedIn: 'root'
})
export class CpfhubService {
 private readonly apiUrl = environment.cpfhubApiUrl;

 constructor(private http: HttpClient) {}

 consultarCpf(cpf: string): Observable<CpfResponse> {
 const cpfLimpo = cpf.replace(/\D/g, '');
 return this.http
 .get<CpfResponse>(`${this.apiUrl}/cpf/${cpfLimpo}`)
 .pipe(
 timeout(10000),
 catchError(this.handleError)
 );
 }

 private handleError(error: HttpErrorResponse) {
 let mensagem = 'Erro desconhecido na consulta de CPF.';

 if (error.status === 400) {
 mensagem = 'CPF informado está em formato inválido.';
 } else if (error.status === 401) {
 mensagem = 'Chave de API inválida ou ausente.';
 } else if (error.status === 429) {
 mensagem = 'Limite de requisições excedido. Tente novamente em instantes.';
 } else if (error.status === 500) {
 mensagem = 'Erro interno do servidor. Tente novamente.';
 }

 return throwError(() => new Error(mensagem));
 }
}
```

---

## Validação local dos dígitos verificadores

Antes de consumir uma consulta da API, é boa prática validar os dígitos verificadores localmente. Isso evita gastar consultas com CPFs matematicamente inválidos.

```typescript
// src/app/validators/cpf.validator.ts
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

export function cpfValidator(): ValidatorFn {
 return (control: AbstractControl): ValidationErrors | null => {
 const cpf = control.value?.replace(/\D/g, '');

 if (!cpf || cpf.length !== 11) {
 return { cpfInvalido: true };
 }

 // Rejeitar sequências repetidas
 if (/^(\d)\1{10}$/.test(cpf)) {
 return { cpfInvalido: true };
 }

 // Validar primeiro dígito verificador
 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 { cpfInvalido: true };
 }

 // Validar segundo dígito verificador
 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 { cpfInvalido: true };
 }

 return null;
 };
}
```

---

## Criando o componente de formulário

Com o service, o interceptor e o validator prontos, vamos criar o componente que une tudo.

### Template HTML

```html
<!-- src/app/components/cpf-form/cpf-form.component.html -->
<form [formGroup]="cpfForm" (ngSubmit)="onSubmit()">
 <div class="campo">
 <label for="cpf">CPF</label>
 <input
 id="cpf"
 formControlName="cpf"
 placeholder="000.000.000-00"
 maxlength="14"
 />
 <span *ngIf="cpfForm.get('cpf')?.hasError('cpfInvalido')" class="erro">
 CPF inválido.
 </span>
 </div>

 <button type="submit" [disabled]="cpfForm.invalid || carregando">
 {{ carregando ? 'Consultando...' : 'Consultar CPF' }}
 </button>
</form>

<div *ngIf="dadosCpf" class="resultado">
 <h3>Dados do titular</h3>
 <p><strong>Nome:</strong> {{ dadosCpf.name }}</p>
 <p><strong>Gênero:</strong> {{ dadosCpf.gender === 'M' ? 'Masculino' : 'Feminino' }}</p>
 <p><strong>Data de nascimento:</strong> {{ dadosCpf.birthDate }}</p>
</div>

<div *ngIf="erro" class="erro-consulta">
 <p>{{ erro }}</p>
</div>
```

### Componente TypeScript

```typescript
// src/app/components/cpf-form/cpf-form.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { CpfhubService } from '../../services/cpfhub.service';
import { CpfData } from '../../models/cpf-response.model';
import { cpfValidator } from '../../validators/cpf.validator';

@Component({
 selector: 'app-cpf-form',
 templateUrl: './cpf-form.component.html'
})
export class CpfFormComponent {
 cpfForm: FormGroup;
 dadosCpf: CpfData | null = null;
 carregando = false;
 erro: string | null = null;

 constructor(
 private fb: FormBuilder,
 private cpfhubService: CpfhubService
 ) {
 this.cpfForm = this.fb.group({
 cpf: ['', [Validators.required, cpfValidator()]]
 });
 }

 onSubmit(): void {
 if (this.cpfForm.invalid) return;

 this.carregando = true;
 this.erro = null;
 this.dadosCpf = null;

 const cpf = this.cpfForm.get('cpf')?.value;

 this.cpfhubService.consultarCpf(cpf).subscribe({
 next: (response) => {
 this.dadosCpf = response.data;
 this.carregando = false;
 },
 error: (err) => {
 this.erro = err.message;
 this.carregando = false;
 }
 });
 }
}
```

---

## Testando a integração

### Teste unitário do service

```typescript
// src/app/services/cpfhub.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { CpfhubService } from './cpfhub.service';

describe('CpfhubService', () => {
 let service: CpfhubService;
 let httpMock: HttpTestingController;

 beforeEach(() => {
 TestBed.configureTestingModule({
 imports: [HttpClientTestingModule],
 providers: [CpfhubService]
 });
 service = TestBed.inject(CpfhubService);
 httpMock = TestBed.inject(HttpTestingController);
 });

 it('deve consultar CPF com sucesso', () => {
 const mockResponse = {
 success: true,
 data: {
 cpf: '12345678900',
 name: 'João da Silva',
 nameUpper: 'JOAO DA SILVA',
 gender: 'M',
 birthDate: '15/06/1990',
 day: 15,
 month: 6,
 year: 1990
 }
 };

 service.consultarCpf('123.456.789-00').subscribe((res) => {
 expect(res.success).toBeTrue();
 expect(res.data.name).toBe('João da Silva');
 });

 const req = httpMock.expectOne(
 'https://api.cpfhub.io/cpf/12345678900'
 );
 expect(req.request.method).toBe('GET');
 req.flush(mockResponse);
 });
});
```

---

## Boas práticas de segurança

### Nunca exponha a chave de API no frontend

O exemplo acima armazena a chave nas variáveis de ambiente do Angular, mas lembre-se: essas variáveis são incluídas no bundle de produção e ficam visíveis no código-fonte do navegador.

Para produção, a abordagem recomendada é criar um endpoint backend (BFF -- Backend for Frontend) que faz a chamada à API da CPFHub.io e repassa os dados ao frontend:

```typescript
// Backend (Express.js como BFF)
const express = require('express');
const app = express();

app.get('/api/cpf/:cpf', async (req, res) => {
 const { cpf } = req.params;
 const response = await fetch(
 `https://api.cpfhub.io/cpf/${cpf}`,
 {
 headers: {
 'x-api-key': process.env.CPFHUB_API_KEY,
 'Accept': 'application/json'
 }
 }
 );
 const data = await response.json();
 res.json(data);
});

app.listen(3000);
```

Dessa forma, a chave de API fica protegida no servidor e o frontend consome apenas o seu BFF.

---

## 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

- [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 validação de CPF em aplicações Angular é um processo estruturado quando se utilizam services, interceptors e reactive forms. O service encapsula a lógica de consulta, o interceptor centraliza a autenticação e os reactive forms garantem uma experiência fluida para o usuário. Acesse [cpfhub.io](https://www.cpfhub.io/) para criar sua conta — o plano gratuito com 50 consultas mensais está disponível sem cartão de crédito para validar a integração antes de ir a produção.

