What is a Spring HTTP Interface (declarative HTTP client), and how do you declare one with @HttpExchange?
answer
- interface + @GetExchange = declarative call
- @HttpExchange type-level shared config
- params: @PathVariable/@RequestParam/@RequestBody
- proxy from HttpServiceProxyFactory
- like Feign, built into Spring 6
basics
~10 sYou define a Java interface with methods annotated like @GetExchange("/users/{id}"). Spring generates a proxy that turns each call into a real HTTP request, so you never write HTTP plumbing by hand.
solid answer
~40 sAn HTTP Interface is a plain Java/Kotlin interface where each method describes a remote HTTP call using annotations: @HttpExchange on the type for shared config (base path, content type) and @GetExchange / @PostExchange / @PutExchange / @DeleteExchange / @PatchExchange on methods. Method parameters map to request parts via @PathVariable, @RequestParam, @RequestBody, @RequestHeader. Spring's HttpServiceProxyFactory creates a dynamic proxy implementing that interface, backed by an adapter over a RestClient, WebClient, or RestTemplate. Calling a method executes the HTTP request, deserializes the response into the return type, and hands it back. It's the declarative equivalent of hand-writing RestClient calls — similar in spirit to OpenFeign, but built into Spring Framework 6+ with no extra dependency.
code
java · 15 lines@HttpExchange(url = "/users", accept = "application/json")
public interface UserClient {
@GetExchange("/{id}")
User getById(@PathVariable long id);
@GetExchange
List<User> search(@RequestParam String name);
@PostExchange
User create(@RequestBody NewUser body);
@DeleteExchange("/{id}")
void delete(@PathVariable long id);
}go deeper
Know it's a declarative interface with @GetExchange-style methods that Spring turns into HTTP calls.
Know the full annotation set and parameter binding (@PathVariable/@RequestParam/@RequestBody).
Explain proxy creation via HttpServiceProxyFactory and adapter choice, plus return-type options.
Weigh it against Feign/RestClient directly, discuss registration strategy, resilience, and testing across a codebase.
## What it is An **HTTP Interface** is Spring Framework's declarative HTTP client, introduced in Spring 6.0. Instead of imperatively building requests with `RestTemplate` or `RestClient`, you declare an **interface** whose methods each describe one remote endpoint. Spring generates a runtime **dynamic proxy** that implements the interface; each method invocation is translated into an actual HTTP request/response. ## The annotations - **`@HttpExchange`** — placed on the interface (type level) to hold shared settings such as a base `url`, default `contentType`, and `accept`. It can also be used directly on a method with an explicit `method = "GET"`. - Method-level shortcuts, each a meta-annotation of `@HttpExchange` with the HTTP method pre-set: - `@GetExchange` - `@PostExchange` - `@PutExchange` - `@DeleteExchange` - `@PatchExchange` - Their key attributes: `url` (path, appended to the type-level url), `contentType`, `accept`. ## Parameter binding Method parameters are mapped to parts of the request with familiar Spring MVC-style annotations: - `@PathVariable` — fills `{placeholders}` in the url. - `@RequestParam` — query parameters (or form data for form content type). - `@RequestBody` — serialized request payload (JSON by default via the underlying message converters/codecs). - `@RequestHeader`, `@CookieValue`, `@RequestPart` (multipart). - Certain **special parameter types** are handled automatically: a `URI` argument overrides the url, an `HttpMethod` argument overrides the method, and `MultipartFile` / `MultiValueMap` support form and multipart uploads. ## How the proxy is made (preview — deeper in other questions) You don't `new` the interface. You obtain an implementation from `HttpServiceProxyFactory`, configured with an **exchange adapter** (`RestClientAdapter`, `WebClientAdapter`, or `RestTemplateAdapter`) that wraps the real HTTP client: ```java RestClient restClient = RestClient.create("https://api.example.com"); HttpServiceProxyFactory factory = HttpServiceProxyFactory .builderFor(RestClientAdapter.create(restClient)).build(); UserClient client = factory.createClient(UserClient.class); ``` ## Return types - With a **blocking adapter** (RestClient / RestTemplate): the method can return the deserialized body (`User`), `ResponseEntity<User>`, `void`, a collection, etc. - With the **reactive** `WebClientAdapter`: it can additionally return `Mono<T>` / `Flux<T>`. ## Why use it - Removes boilerplate: no manual URL building, header setting, or response extraction. - Type-safe and testable: the interface is easy to mock in unit tests of your service code. - Consistent: reuses Spring's message converters, so JSON (Jackson) serialization "just works." - Comparable to Netflix/OpenFeign, but native to Spring with no external library. ## Gotchas - It is **not** a Spring bean automatically in older setups — you must register the proxy as a bean (or use Boot's newer auto-registration support) before injecting it. - The interface only *describes* calls; all real behavior (timeouts, base URL, interceptors, auth) is configured on the **underlying** RestClient/WebClient, not the interface. - Don't confuse it with `@FeignClient` (that's Spring Cloud OpenFeign, a separate project).
- Which annotation carries shared settings for the whole interface, and what can it set?`@HttpExchange` at the type level. It supplies a base `url` prepended to method urls, plus default `contentType` and `accept`. Method annotations like `@GetExchange` inherit/override these.
- How is this different from Spring Cloud OpenFeign's @FeignClient?HTTP Interfaces are core Spring Framework 6+, using HttpServiceProxyFactory over RestClient/WebClient/RestTemplate, no extra dependency. @FeignClient is a separate Spring Cloud project wrapping OpenFeign. They solve the same declarative-client problem but are distinct libraries.
saying these in an interview costs you the question
- Thinking you implement the interface yourself with `new` or an `@Component`.
- Confusing @HttpExchange with @FeignClient / assuming it needs Spring Cloud.
- Believing the annotations configure timeouts or base URL (those live on the RestClient/WebClient).