Backend Development 13 min read

10 Ways to Call Third-Party APIs in Spring Boot 3.3 – Full Code Guide

This article reviews ten practical methods for invoking third-party HTTP services in Spring Boot 3.3, covering plain JDK URL, HttpClient, Apache HttpClient, OkHttp, RestTemplate, WebClient, RestClient, Http Interface, OpenFeign, and Gateway proxy, each with code samples and key advantages.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
10 Ways to Call Third-Party APIs in Spring Boot 3.3 – Full Code Guide

Environment: SpringBoot 3.3.0

1. Introduction

Calling third‑party interfaces is common in projects; the choice of method follows the company’s tech stack and architecture guidelines. RESTful API, Feign, Apache HttpClient, etc., each have scenarios and advantages, and selecting the right one improves development efficiency and system performance.

2. Practical Examples

2.1 JDK URL

<code>URL url = URI.create("http://localhost:8002/api/data").toURL();
URLConnection connection = url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream inputStream = connection.getInputStream();
String ret = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println(ret);
</code>

This approach is cumbersome and lacks support for request parameters, making it time‑consuming for complex APIs.

2.2 JDK HttpClient (Java 11+)

<code>URI uri = URI.create("http://localhost:8002/api/data");
HttpClient client = HttpClient.newBuilder()
  .connectTimeout(Duration.ofSeconds(3))
  .executor(Executors.newCachedThreadPool())
  .build();
HttpRequest request = HttpRequest.newBuilder(uri)
  .GET()
  .build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.body());
</code>

HttpClient offers better configurability but is still a bit verbose.

2.3 Apache HttpClient

<code>HttpGet httpget = new HttpGet("http://localhost:8002/api/data");
CloseableHttpClient client = HttpClients.custom().build();
HttpClientResponseHandler<String> responseHandler = new BasicHttpClientResponseHandler();
String ret = client.execute(httpget, responseHandler);
System.out.println(ret);
</code>

Apache HttpClient 5 supports HTTP/2, high customisation, and asynchronous requests:

<code>CloseableHttpAsyncClient client = HttpAsyncClients.custom().build();
client.start();
SimpleHttpRequest request = SimpleRequestBuilder.get()
  .setHttpHost(HttpHost.create("http://localhost:8002"))
  .setPath("/api/data")
  .build();
FutureCallback<SimpleHttpResponse> callback = new FutureCallback<SimpleHttpResponse>() {
  @Override public void failed(Exception ex) { System.err.printf("Request failed: %s%n", ex.getMessage()); }
  @Override public void completed(SimpleHttpResponse result) { System.out.printf("Thread: %s, completed...%n", Thread.currentThread().getName()); }
  public void cancelled() {}
};
Future<SimpleHttpResponse> future = client.execute(request, callback);
System.out.println(new String(future.get().getBodyBytes(), StandardCharsets.UTF_8));
client.close(CloseMode.GRACEFUL);
</code>

2.4 OkHttp

HTTP/2 support allows socket sharing for all requests to the same host.

Connection pool reduces latency when HTTP/2 is unavailable.

Transparent GZIP reduces download size.

Response cache eliminates duplicate network calls.

Simple synchronous call:

<code>URL url = URI.create("http://localhost:8002/api/data").toURL();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
  System.out.println(response.body().string());
}
</code>

Asynchronous call:

<code>URL url = URI.create("http://localhost:8002/api/data").toURL();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
  public void onResponse(Call call, Response response) throws IOException {
    System.out.printf("Thread: %s, content: %s%n", Thread.currentThread().getName(), response.body().string());
  }
  public void onFailure(Call call, IOException e) {
    System.err.printf("Request failed: %s%n", e.getMessage());
  }
});
</code>

2.5 RestTemplate

RestTemplate is the most commonly used client in Spring projects, providing a high‑level API over HTTP libraries.

<code>RestTemplate restTemplate = new RestTemplate();
Map ret = restTemplate.getForObject(URI.create("http://localhost:8002/api/data"), Map.class);
System.out.println(ret);
</code>

Using RestTemplateBuilder for additional configuration (timeouts, interceptors, etc.)

<code>RestTemplate restTemplate = new RestTemplateBuilder()
  .setConnectTimeout(Duration.ofSeconds(5))
  .setReadTimeout(Duration.ofSeconds(5))
  .interceptors(List.of())
  .build();
Map ret = restTemplate.getForObject(URI.create("http://localhost:8002/api/data"), Map.class);
System.out.println(ret);
</code>

By default RestTemplate uses JDK URL, but it can be switched to Apache HttpClient or OkHttp.

2.6 WebClient

WebClient is a non‑blocking, reactive HTTP client introduced in Spring 5, offering a RestTemplate alternative with support for synchronous, asynchronous, and streaming scenarios.

Non‑blocking I/O

Reactive back‑pressure

High concurrency with fewer resources

Functional, lambda‑friendly API

Supports both sync and async interactions

Streaming request/response bodies

Built‑in HTTP client options include Reactor Netty, JDK HttpClient, Jetty Reactive HttpClient, Apache HttpComponents, or any custom ClientHttpConnector.

Simple request example:

<code>WebClient client = WebClient.create("http://localhost:8002");
client.get()
  .uri("/api/data")
  .retrieve()
  .bodyToMono(String.class)
  .subscribe(System.out::println);
</code>

Configuration with timeout and error handling:

<code>HttpClient httpClient = HttpClient.create()
  .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
WebClient client = WebClient.builder()
  .clientConnector(new ReactorClientHttpConnector(httpClient))
  .build();
client.get()
  .uri("http://localhost:8002/api/data")
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError, resp -> Mono.error(new RuntimeException("Client error")))
  .bodyToMono(String.class)
  .subscribe(System.out::println);
System.in.read();
</code>

2.7 RestClient (Spring 6.1+)

RestClient is a new thread‑safe API introduced in Spring 6.1.

<code>RestClient client = RestClient.create();
ParameterizedTypeReference<Map<String, Object>> bodyType = new ParameterizedTypeReference<>() {};
Map<String, Object> ret = client.get()
  .uri(URI.create("http://localhost:8002/api/data"))
  .retrieve()
  .body(bodyType);
</code>

Builder allows default headers, interceptors, and base URL configuration.

<code>RestClient client = RestClient.builder()
  .defaultHeader("x-api-token", "aaabbbccc111222")
  .requestInterceptor((request, body, execution) -> execution.execute(request, body))
  .baseUrl("http://localhost:8002")
  .build();
</code>

2.8 Http Interface

Define a Java interface with @HttpExchange methods and create a proxy via HttpServiceProxyFactory, which uses RestClient or WebClient under the hood.

<code>// Interface definition
public interface RemoteClient {
  @GetExchange("/api/data")
  Map<String, Object> queryInfo();
}

// Invocation
RestClient restClient = RestClient.builder().baseUrl("http://localhost:8002").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(RestClientAdapter.create(restClient)).build();
RemoteClient client = factory.createClient(RemoteClient.class);
System.out.println(client.queryInfo());
</code>

2.9 OpenFeign (stand‑alone)

OpenFeign (not Spring Cloud OpenFeign) can be used directly.

<code>&lt;dependency&gt;
  &lt;groupId&gt;io.github.openfeign&lt;/groupId&gt;
  &lt;artifactId&gt;feign-core&lt;/artifactId&gt;
  &lt;version&gt;13.2.1&lt;/version&gt;
&lt;/dependency&gt;
</code>
<code>// Interface definition
public interface RemoteClient {
  @RequestLine("GET /api/data")
  Map<String, Object> queryInfo();
}

// Call
RemoteClient client = Feign.builder()
  .decoder(new JacksonDecoder())
  .target(RemoteClient.class, "http://localhost:8002");
Map<String, Object> ret = client.queryInfo();
</code>

2.10 Gateway Proxy

Gateway MVC can act as a proxy using ProxyExchange.

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
  &lt;artifactId&gt;spring-cloud-gateway-mvc&lt;/artifactId&gt;
&lt;/dependency&gt;
</code>
<code>private URI uri = URI.create("http://localhost:8002");

@GetMapping("/api")
public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
  return proxy.uri(uri.toString() + "/api/data").get();
}
</code>
JavaSpring BootfeignRestTemplateWebClientAPI IntegrationOkHttpHTTP Client
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.