Como Criar um Microsserviço de Validação de CPF com Spring Boot e Docker

Aprenda a criar um microsserviço de validação de CPF com Spring Boot e Docker, com endpoints REST, health checks, métricas e containerização.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como Criar um Microsserviço de Validação de CPF com Spring Boot e Docker

Para criar um microsserviço de validação de CPF com Spring Boot e Docker, estruture o projeto em camadas (controller, service, config, DTO), implemente a lógica de validação algorítmica localmente e delegue a consulta de dados à API CPFHub.io, depois containerize com multi-stage build para uma imagem de produção enxuta (~200MB). O Spring Actuator entrega health checks e métricas prontas sem configuração adicional.

Introdução

Microsserviços são a arquitetura padrão para sistemas modernos, e um serviço dedicado à validação de CPF centraliza essa responsabilidade para toda a organização. O Spring Boot simplifica a criação do serviço, enquanto o Docker garante portabilidade e consistência entre ambientes.

Estrutura do projeto

O projeto segue a estrutura padrão do Spring Boot com separação por camada.

// Estrutura de diretórios
// cpf-service/
// src/main/java/com/cpfservice/
// CpfServiceApplication.java
// config/
// CpfHubConfig.java
// controller/
// CpfController.java
// HealthController.java
// service/
// CpfValidationService.java
// dto/
// CpfRequest.java
// CpfResponse.java
// exception/
// GlobalExceptionHandler.java
// src/main/resources/
// application.yml
// Dockerfile
// docker-compose.yml
CamadaResponsabilidadePacote
ControllerEndpoints RESTcontroller
ServiceLógica de negócioservice
ConfigConfiguração de beansconfig
DTOObjetos de transferênciadto
ExceptionTratamento global de errosexception

Configuração e DTOs

Configure a aplicação e defina os objetos de transferência de dados.

// application.yml
// server:
// port: 8080
// cpfhub:
// api-key: ${CPFHUB_API_KEY}
// base-url: https://api.cpfhub.io
// timeout: 10000
// management:
// endpoints:
// web:
// exposure:
// include: health,metrics,info
// endpoint:
// health:
// show-details: always

// CpfHubConfig.java
package com.cpfservice.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;

@Configuration
public class CpfHubConfig {

    @Value("${cpfhub.timeout:10000}")
    private int timeout;

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
    .setConnectTimeout(Duration.ofMillis(5000))
    .setReadTimeout(Duration.ofMillis(timeout))
    .build();
    }
}

// CpfRequest.java
package com.cpfservice.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public record CpfRequest(
    @NotBlank(message = "CPF e obrigatorio")
    @Pattern(
    regexp = "\\d{11}|\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}",
    message = "CPF deve estar no formato correto"
    )
    String cpf
) {}

// CpfResponse.java
public record CpfResponse(
    boolean sucesso,
    String fonte,
    DadosCpf dados,
    String erro
) {
    public record DadosCpf(
    String cpf,
    String name,
    String nameUpper,
    String gender,
    String birthDate,
    int day,
    int month,
    int year
    ) {}
}

Service layer

O service implementa a lógica de validação algorítmica e consulta via API.

package com.cpfservice.service;

import com.cpfservice.dto.CpfResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class CpfValidationService {

    private final RestTemplate restTemplate;
    private final String apiKey;
    private final String baseUrl;
    private final ObjectMapper mapper;

    public CpfValidationService(
    RestTemplate restTemplate,
    @Value("${cpfhub.api-key}") String apiKey,
    @Value("${cpfhub.base-url}") String baseUrl) {
    this.restTemplate = restTemplate;
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
    this.mapper = new ObjectMapper();
    }

    public CpfResponse validar(String cpf) {
    String cpfLimpo = cpf.replaceAll("\\D", "");

    // Validação algorítmica
    if (!validarAlgoritmo(cpfLimpo)) {
    return new CpfResponse(
    false, "algoritmo", null,
    "CPF invalido (digitos verificadores)"
    );
    }

    // Consulta via API
    try {
    HttpHeaders headers = new HttpHeaders();
    headers.set("x-api-key", apiKey);

    ResponseEntity<String> response =
    restTemplate.exchange(
    baseUrl + "/cpf/" + cpfLimpo,
    HttpMethod.GET,
    new HttpEntity<>(headers),
    String.class
    );

    JsonNode root = mapper.readTree(response.getBody());

    if (root.get("success").asBoolean()) {
    JsonNode data = root.get("data");
    CpfResponse.DadosCpf dados =
    new CpfResponse.DadosCpf(
    data.get("cpf").asText(),
    data.get("name").asText(),
    data.get("nameUpper").asText(),
    data.get("gender").asText(),
    data.get("birthDate").asText(),
    data.get("day").asInt(),
    data.get("month").asInt(),
    data.get("year").asInt()
    );
    return new CpfResponse(true, "api", dados, null);
    }

    return new CpfResponse(
    false, "api", null, "CPF nao encontrado"
    );
    } catch (Exception e) {
    return new CpfResponse(
    false, "erro", null,
    "Erro na consulta: " + e.getMessage()
    );
    }
    }

    private boolean validarAlgoritmo(String cpf) {
    if (cpf.length() != 11) return false;
    if (cpf.chars().distinct().count() == 1) return false;

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

    soma = 0;
    for (int i = 0; i < 10; i++) {
    soma += Character.getNumericValue(cpf.charAt(i))
    * (11 - i);
    }
    resto = (soma * 10) % 11;
    if (resto == 10) resto = 0;
    return resto == Character.getNumericValue(cpf.charAt(10));
    }
}

Controller e exception handler

O controller expõe os endpoints REST para validação de CPF.

package com.cpfservice.controller;

import com.cpfservice.dto.CpfResponse;
import com.cpfservice.service.CpfValidationService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/v1/cpf")
public class CpfController {

    private final CpfValidationService service;

    public CpfController(CpfValidationService service) {
    this.service = service;
    }

    @GetMapping("/{cpf}")
    public ResponseEntity<CpfResponse> validar(
    @PathVariable String cpf) {
    CpfResponse resultado = service.validar(cpf);
    int status = resultado.sucesso() ? 200 : 404;
    return ResponseEntity.status(status).body(resultado);
    }

    @PostMapping("/lote")
    public ResponseEntity<Map<String, Object>> validarLote(
    @RequestBody List<String> cpfs) {
    List<CpfResponse> resultados = cpfs.stream()
    .map(service::validar)
    .toList();

    long validos = resultados.stream()
    .filter(CpfResponse::sucesso).count();

    return ResponseEntity.ok(Map.of(
    "total", cpfs.size(),
    "validos", validos,
    "invalidos", cpfs.size() - validos,
    "resultados", resultados
    ));
    }
}
EndpointMétodoDescrição
/api/v1/cpf/{cpf}GETValidar CPF individual
/api/v1/cpf/lotePOSTValidar lote de CPFs
/actuator/healthGETHealth check
/actuator/metricsGETMétricas da aplicação

Dockerfile e Docker Compose

Containerize o serviço com multi-stage build para uma imagem otimizada. A documentação oficial do Docker recomenda essa abordagem para reduzir o tamanho da imagem final em aplicações JVM.

# Dockerfile
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
    CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]
# docker-compose.yml
version: "3.8"

services:
    cpf-service:
    build: .
    ports:
    - "8080:8080"
    environment:
    - CPFHUB_API_KEY=${CPFHUB_API_KEY}
    - SPRING_PROFILES_ACTIVE=prod
    - JAVA_OPTS=-Xmx256m -Xms128m
    healthcheck:
    test: ["CMD", "wget", "-qO-", "http://localhost:8080/actuator/health"]
    interval: 30s
    timeout: 3s
    retries: 3
    restart: unless-stopped
    deploy:
    resources:
    limits:
    memory: 512M
    cpus: "0.5"
EstágioImagemTamanho
Buildereclipse-temurin:21-jdk-alpine~400MB
Runtimeeclipse-temurin:21-jre-alpine~180MB
Imagem finalCom aplicação~200MB

Perguntas frequentes

Por que usar um microsserviço dedicado em vez de validar o CPF diretamente em cada serviço?

Centralizar a validação em um microsserviço elimina duplicação de código, garante consistência nas regras de negócio e facilita auditoria. Quando as regras mudam (novo provider de API, lógica de cache, requisitos de PLD/FT), a atualização ocorre em um único ponto sem impactar os consumidores.

Como o Spring Actuator ajuda em produção?

O Actuator expõe endpoints /actuator/health e /actuator/metrics que orquestradores como Kubernetes e balanceadores de carga usam para saber se o serviço está saudável. O health check configurado no Dockerfile e no docker-compose.yml reinicia o container automaticamente em caso de falha.

Como lidar com timeouts nas chamadas à API CPFHub.io?

Configure setConnectTimeout (recomendado: 5s) e setReadTimeout (recomendado: 10s) no RestTemplateBuilder. A latência típica da CPFHub.io é ~900ms, então um timeout de 10s cobre picos ocasionais sem prejudicar a experiência. Em caso de timeout, retorne um erro controlado em vez de deixar a thread travar.

A API CPFHub.io bloqueia requisições se o limite do plano for atingido?

Não. Se o volume de consultas ultrapassar o limite do plano contratado, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional. Isso garante que o microsserviço nunca perca disponibilidade por causa de cotas — apenas revise o faturamento em app.cpfhub.io/settings/billing.


Conclusão

Um microsserviço de validação de CPF com Spring Boot e Docker centraliza a responsabilidade de validação, oferecendo endpoints REST consistentes para toda a organização. O Spring Actuator fornece health checks e métricas prontas para produção, enquanto o Docker garante portabilidade e consistência entre ambientes. Essa arquitetura permite escalar o serviço independentemente e atualizá-lo sem impactar os consumidores.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a API CPFHub.io ao seu microsserviço Spring Boot em menos de 30 minutos.

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