Como Usar RestTemplate e WebClient para Consultar CPF via API em Java

Compare RestTemplate e WebClient para consultar a API de CPF em Java Spring, com exemplos práticos de configuração, uso e tratamento de erros.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como Usar RestTemplate e WebClient para Consultar CPF via API em Java

Para consultar a API de CPF em Java Spring, use RestTemplate para aplicações MVC tradicionais com baixo volume de consultas, ou WebClient para projetos WebFlux e cenários de alta concorrência. O RestTemplate é síncrono e mais simples de configurar; o WebClient é reativo, não-bloqueante e processa lotes de CPFs em paralelo, reduzindo o tempo de validação de ~20 segundos para ~2 segundos em lotes de 100 documentos.

Introdução

O ecossistema Spring oferece duas opções principais para consumir APIs REST: o RestTemplate, síncrono e amplamente utilizado, e o WebClient, reativo e não-bloqueante. Ambos são capazes de consumir a API de CPF de forma eficiente, mas cada um tem características que o tornam mais adequado para cenários específicos.


Comparação entre RestTemplate e WebClient

Entender as diferenças fundamentais ajuda a escolher a ferramenta certa.

CaracterísticaRestTemplateWebClient
ModeloSíncrono (bloqueante)Reativo (não-bloqueante)
IntroduçãoSpring 3.0Spring 5.0 (WebFlux)
StatusEm modo de manutençãoRecomendado para novos projetos
Thread por requisiçãoSimNão (event loop)
Adequado paraAPIs simples, baixo volumeAlta concorrência, streaming
Curva de aprendizadoBaixaMédia (programação reativa)
Dependênciaspring-boot-starter-webspring-boot-starter-webflux

Implementação com RestTemplate

O RestTemplate é direto e familiar para desenvolvedores Java.

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;

@Service
public class CpfRestTemplateService {

    private final RestTemplate restTemplate;
    private final String apiKey;

    public CpfRestTemplateService(
    RestTemplateBuilder builder,
    @Value("${cpfhub.api-key}") String apiKey) {
    this.restTemplate = builder
    .setConnectTimeout(Duration.ofSeconds(5))
    .setReadTimeout(Duration.ofSeconds(10))
    .build();
    this.apiKey = apiKey;
    }

    public CpfData consultar(String cpf) {
    String cpfLimpo = cpf.replaceAll("\\D", "");

    HttpHeaders headers = new HttpHeaders();
    headers.set("x-api-key", apiKey);
    headers.setContentType(MediaType.APPLICATION_JSON);

    HttpEntity<Void> entity = new HttpEntity<>(headers);

    try {
    ResponseEntity<CpfResponse> response =
    restTemplate.exchange(
    "https://api.cpfhub.io/cpf/" + cpfLimpo,
    HttpMethod.GET,
    entity,
    CpfResponse.class
    );

    CpfResponse body = response.getBody();
    if (body != null && body.isSuccess()) {
    return body.getData();
    }
    throw new CpfNaoEncontradoException(
    "CPF nao encontrado"
    );

    } catch (HttpClientErrorException.Unauthorized e) {
    throw new ApiException("API key invalida");
    } catch (HttpClientErrorException e) {
    throw new ApiException(
    "Erro HTTP: " + e.getStatusCode()
    );
    }
    }

    public List<CpfData> consultarLote(List<String> cpfs) {
    return cpfs.stream()
    .map(this::consultar)
    .toList();
    }
}

Implementação com WebClient

O WebClient oferece uma API fluente e suporte reativo.

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;

@Service
public class CpfWebClientService {

    private final WebClient webClient;

    public CpfWebClientService(
    @Value("${cpfhub.api-key}") String apiKey) {
    this.webClient = WebClient.builder()
    .baseUrl("https://api.cpfhub.io")
    .defaultHeader("x-api-key", apiKey)
    .defaultHeader("Content-Type", "application/json")
    .build();
    }

    public Mono<CpfData> consultar(String cpf) {
    String cpfLimpo = cpf.replaceAll("\\D", "");

    return webClient.get()
    .uri("/cpf/{cpf}", cpfLimpo)
    .retrieve()
    .bodyToMono(CpfResponse.class)
    .timeout(Duration.ofSeconds(10))
    .flatMap(response -> {
    if (response.isSuccess()) {
    return Mono.just(response.getData());
    }
    return Mono.error(
    new CpfNaoEncontradoException(
    "CPF nao encontrado"
    )
    );
    })
    .onErrorResume(
    WebClientResponseException.Unauthorized.class,
    e -> Mono.error(
    new ApiException("API key invalida")
    )
    );
    }

    public Flux<CpfData> consultarLote(List<String> cpfs) {
    return Flux.fromIterable(cpfs)
    .flatMap(this::consultar, 10) // 10 em paralelo
    .onErrorContinue((erro, cpf) ->
    System.err.println(
    "Erro no CPF " + cpf + ": " + erro.getMessage()
    )
    );
    }

    // Versão bloqueante para uso em contextos síncronos
    public CpfData consultarSync(String cpf) {
    return consultar(cpf).block();
    }
}

Consulta em lote: comparação de performance

A maior diferença aparece no processamento em lote, onde o WebClient brilha.

// RestTemplate: sequencial (bloqueante)
public List<CpfData> loteSincrono(List<String> cpfs) {
    return cpfs.stream()
    .map(this::consultar)
    .toList();
}

// WebClient: paralelo (não-bloqueante)
public List<CpfData> loteReativo(List<String> cpfs) {
    return Flux.fromIterable(cpfs)
    .flatMap(
    cpf -> consultar(cpf)
    .onErrorResume(e -> Mono.empty()),
    10 // concorrência máxima
    )
    .collectList()
    .block();
}
Métrica (100 CPFs)RestTemplateWebClient (10 conc.)
Tempo total~20s~2s
Threads utilizadas1~10 (event loop)
Memória consumida~50MB~20MB
CPU utilizadaBaixa (espera I/O)Eficiente
Adequado paraLotes pequenosLotes grandes

Retry e resiliência

Ambos os clientes suportam retry, mas com APIs diferentes.

// Retry com RestTemplate (usando Spring Retry)
@Retryable(
    retryFor = {ApiException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000, multiplier = 2)
)
public CpfData consultarComRetry(String cpf) {
    return consultar(cpf);
}

// Retry com WebClient (nativo Reactor)
public Mono<CpfData> consultarComRetryReativo(String cpf) {
    return consultar(cpf)
    .retryWhen(
    Retry.backoff(3, Duration.ofSeconds(1))
    .maxBackoff(Duration.ofSeconds(10))
    .filter(throwable ->
    throwable instanceof ApiException
    )
    .doBeforeRetry(signal ->
    System.out.println(
    "Retentativa " + signal.totalRetries()
    )
    )
    );
}

Quando usar cada um

A escolha depende do contexto da aplicação e do padrão de uso.

CenárioRecomendaçãoJustificativa
Aplicação Spring MVC tradicionalRestTemplateMais simples, sem necessidade de reatividade
Aplicação Spring WebFluxWebClientNativo e não-bloqueante
Consultas individuais esporádicasRestTemplateOverhead mínimo
Processamento em lote de CPFsWebClientConcorrência eficiente
Migração de sistema legadoRestTemplateMenor impacto na arquitetura
Novo projeto greenfieldWebClientRecomendação oficial do Spring

RestTemplate -- escolha quando a simplicidade é prioridade e o volume de consultas é baixo.

WebClient -- escolha quando a aplicação precisa de alta concorrência ou já usa Spring WebFlux.


Perguntas frequentes

Quando devo escolher RestTemplate em vez de WebClient para consultar a API de CPF?

Escolha RestTemplate quando a aplicação já usa Spring MVC (não WebFlux), o volume de consultas é baixo (validações individuais no cadastro, por exemplo) e a equipe não tem experiência com programação reativa. O RestTemplate é síncrono, bloqueante e mais fácil de depurar. Para novos projetos ou cenários de lote, o WebClient é a recomendação oficial do Spring desde a versão 5.

Como configurar timeout no RestTemplate e no WebClient para a API de CPF?

No RestTemplate, use RestTemplateBuilder.setConnectTimeout(Duration.ofSeconds(5)).setReadTimeout(Duration.ofSeconds(10)). No WebClient, adicione .timeout(Duration.ofSeconds(10)) na cadeia de chamada do Mono. A API da CPFHub.io tem latência de ~900ms, portanto timeouts de 10 segundos de leitura oferecem margem segura sem prejudicar a experiência do usuário.

A API da CPFHub.io bloqueia requisições quando o limite do plano é atingido?

Não. A API da CPFHub.io não retorna erros de bloqueio ao atingir o limite do plano — ela cobra R$0,15 por consulta excedente e continua respondendo normalmente. Portanto, não é necessário implementar lógica de retry específica para limite de cota. O retry deve ser configurado apenas para erros transitórios de rede ou indisponibilidade temporária.

Como processar um lote de 1.000 CPFs de forma eficiente com WebClient?

Use Flux.fromIterable(cpfs).flatMap(this::consultar, N) onde N é o nível de concorrência desejado. Com concorrência 10 e latência de ~900ms por consulta, 1.000 CPFs levam aproximadamente 90 segundos. Ajuste o N conforme os limites do seu plano e a capacidade do servidor. O projeto Reactor tem documentação detalhada sobre controle de concorrência com flatMap.


Conclusão

Tanto RestTemplate quanto WebClient são capazes de consumir a API de CPF de forma eficiente em Java Spring. O RestTemplate é mais simples e familiar, ideal para aplicações tradicionais com baixo volume. O WebClient é a escolha moderna e recomendada, especialmente para cenários de alta concorrência e processamento em lote. Independentemente da escolha, o tratamento de erros, retry e timeout devem ser configurados para garantir a resiliência da integração.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a API de CPF na sua aplicação Spring com RestTemplate ou WebClient 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