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

**Publicado:** 19/09/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/resttemplate-webclient-consultar-cpf-api-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ística | RestTemplate | WebClient |
|---|---|---|
| Modelo | Síncrono (bloqueante) | Reativo (não-bloqueante) |
| Introdução | Spring 3.0 | Spring 5.0 (WebFlux) |
| Status | Em modo de manutenção | Recomendado para novos projetos |
| Thread por requisição | Sim | Não (event loop) |
| Adequado para | APIs simples, baixo volume | Alta concorrência, streaming |
| Curva de aprendizado | Baixa | Média (programação reativa) |
| Dependência | spring-boot-starter-web | spring-boot-starter-webflux |

---

## Implementação com RestTemplate

O RestTemplate é direto e familiar para desenvolvedores Java.

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

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

```java
// 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) | RestTemplate | WebClient (10 conc.) |
|---|---|---|
| Tempo total | ~20s | ~2s |
| Threads utilizadas | 1 | ~10 (event loop) |
| Memória consumida | ~50MB | ~20MB |
| CPU utilizada | Baixa (espera I/O) | Eficiente |
| Adequado para | Lotes pequenos | Lotes grandes |

---

## Retry e resiliência

Ambos os clientes suportam retry, mas com APIs diferentes.

```java
// 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ário | Recomendação | Justificativa |
|---|---|---|
| Aplicação Spring MVC tradicional | RestTemplate | Mais simples, sem necessidade de reatividade |
| Aplicação Spring WebFlux | WebClient | Nativo e não-bloqueante |
| Consultas individuais esporádicas | RestTemplate | Overhead mínimo |
| Processamento em lote de CPFs | WebClient | Concorrência eficiente |
| Migração de sistema legado | RestTemplate | Menor impacto na arquitetura |
| Novo projeto greenfield | WebClient | Recomendaçã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](https://projectreactor.io/) tem documentação detalhada sobre controle de concorrência com `flatMap`.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## 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](https://www.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.

