Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring HTTP service client: the interface is a contract, not a transport policy

Last updated: 1 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

An @HttpExchange interface declares remote requests; its RestClient adapter still needs a base URL, timeouts and error policy.

Keep the interface narrow

A pricing client can expose one quote lookup through @GetExchange and map the path parameter explicitly. HttpServiceProxyFactory creates a typed proxy backed by a RestClient adapter. That removes handwritten request assembly, but the underlying RestClient still decides connection and read timeouts, authentication, status handling and observability. The request factory is where much of the actual I/O behavior is chosen.

Define failure as part of the call

A 404 may mean a product is absent; a 503 may mean the pricing service is unavailable. Do not collapse both into null. Convert known status responses into typed application failures and pass an end-to-end deadline from the caller. Timeout budgeting and status retry rules should be reviewed beside the interface, even though they live in separate configuration.

Test the HTTP wire

Point the proxy at a stub server and verify the URL, encoded path variable, required headers and result mapping. Return a malformed body and a 503 in separate cases. A mocked Java interface call proves neither serialization nor error translation. The code is an integration sketch; add the project's auth interceptor and error handler before production use.

Implementation sketch

Java
@HttpExchange("/v1/prices")
interface PricingClient {
    @GetExchange("/{sku}")
    PriceQuote quote(@PathVariable String sku);
}
RestClient restClient = RestClient.builder()
    .baseUrl("https://pricing.internal")
    .build();
PricingClient client = HttpServiceProxyFactory
    .builderFor(RestClientAdapter.create(restClient)).build()
    .createClient(PricingClient.class);

Cost and verification

The proxy adds small dispatch overhead; network latency, connection pooling, body size and retries dominate. An unbounded read can hold a request thread and pooled connection.

Common Mistakes

  • Do not mistake a typed interface for configured timeouts or status mapping.
  • Do not test only the Java method signature and call it an HTTP integration test.
  • Do not hide remote 404 and 503 responses behind the same null result.

Read next

Spring RestClient request factories: pin the transport you test, Spring HTTP client timeouts: bound the call inside the request deadline, Spring RestClient 503 response: count attempts before adding a retry, Spring HTTP service client retries: an interface cannot prove the server did not commit.

Related boundary

Spring HTTP service groups: configure one host policy for several interfaces

spring
spring-boot
web-apis
http-service-client-contract
Storage details