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.

Redação CPFHub.io
Redação CPFHub.io
··9 min de leitura
Como validar CPF em aplicações Angular usando services e 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 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.

// 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:

// 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.

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

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

// 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.

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

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

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

// 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:

// 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 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.


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

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp