개발일지/SPRINGBOOT

Spring HttpInterface 한 번에 이해하기

recording or reCoding 2025. 12. 19. 14:23

Spring Boot 3 / Spring 6부터 등장한 HttpInterface는 외부 HTTP API 호출 방식을 완전히 바꿔놓았다.

예전처럼 RestTemplate, WebClient 코드를 서비스 안에서 직접 작성하지 않고, 자바 인터페이스 + 애노테이션 선언만으로 HTTP 클라이언트를 만들 수 있다.

이 글에서는 실무 기준으로 HttpInterface의 개념, 동작 구조, 그리고 실제 사용 흐름을 정리한다.


한 줄 요약

HttpInterface는 외부 API 호출을 자바 인터페이스로 추상화하고, Spring이 이를 실제 HTTP 호출로 변환해주는 선언형 HTTP 클라이언트다.

Feign과 매우 유사하지만, Spring Core에서 공식 제공한다는 점이 가장 큰 차이다.

 

왜 HttpInterface가 나왔을까?

외부 API를 호출할 때 보통 다음과 같은 문제가 있었다.

  • WebClient는 유연하지만 코드가 장황해짐
  • HTTP 호출 코드가 서비스 로직과 섞임
  • API 스펙이 코드로 명확히 드러나지 않음

Spring 팀은 이런 문제를 이렇게 해결했다.

“컨트롤러는 애노테이션으로 선언형 정의가 가능한데, 왜 HTTP 클라이언트는 항상 직접 구현해야 하지?”

그 결과가 HttpInterface다.

 

핵심 개념 정리 (중요)

1️⃣ Controller가 아니다 (역할이 반대)

HttpInterface는 모양은 Controller와 비슷하지만, 역할은 완전히 반대다.

구분ControllerHttpInterface

역할 요청을 받음 요청을 보냄
대상 클라이언트 외부 서버
구현 직접 구현 Spring이 자동 생성

즉, 요청을 처리하는 쪽이 아니라 요청을 보내는 계약이다.

 

2️⃣ 구현체가 없는 인터페이스

@HttpExchange(url = "https://api.example.com")
public interface ExternalUserClient {

@GetExchange("/users/{id}")
UserResponse getUser(@PathVariable Long id);
}

이 인터페이스의 특징은 다음과 같다.

  • 구현 클래스 없음
  • @Service 없음
  • 로직 없음

하지만 이 메서드를 호출하면 실제 HTTP 요청이 발생한다.

👉 이유는 Spring이 런타임에 프록시 구현체를 자동 생성하기 때문이다.


3️⃣ 실제 HTTP 호출은 누가 하나?

HttpInterface는 선언만 담당한다.

실제 통신은 다음 중 하나가 수행한다.

  • WebClient (기본)
  • RestClient (Spring 6.1+)

구조를 단순화하면 아래와 같다.

[HttpInterface]
↓
[Spring Proxy]
↓
[WebClient / RestClient]
↓
[외부 API]

 


실무 기준 전체 흐름 (3단계)

1️⃣ 외부 API를 인터페이스로 선언

 

@HttpExchange(url = "https://api.example.com")
public interface ExternalUserClient {

@GetExchange("/users/{id}")
UserResponse getUser(@PathVariable Long id);
}

 

 

이 단계에서는 API 스펙만 정의한다.


2️⃣ 인터페이스를 실제 HTTP 클라이언트로 변환

@Configuration
public class HttpClientConfig {

@Bean
ExternalUserClient externalUserClient(WebClient.Builder builder) {
WebClient webClient = builder.build();

HttpServiceProxyFactory factory =
HttpServiceProxyFactory
.builder(WebClientAdapter.forClient(webClient))
.build();

return factory.createClient(ExternalUserClient.class);
}
}

 

여기서 핵심 역할을 하는 것이 HttpServiceProxyFactory다.

  • 인터페이스를 분석
  • 애노테이션 기반으로 HTTP 요청 구성
  • 동적 프록시 생성

👉 이 시점에 실행 가능한 HTTP 클라이언트 Bean이 만들어진다.


3️⃣ 서비스에서는 그냥 메서드 호출

 

@Service
@RequiredArgsConstructor
public class UserService {

private final ExternalUserClient externalUserClient;

public UserResponse getUser(Long id) {
return externalUserClient.getUser(id);
}
}

 

서비스 입장에서는 이 객체가 HTTP 클라이언트인지조차 알 필요가 없다.

메서드 호출 = HTTP 요청

이라는 구조가 완성된다.


이 구조의 장점 (실무 기준)

  • HTTP 호출 코드와 비즈니스 로직 완전 분리
  • 외부 API 스펙이 인터페이스로 명확히 문서화됨
  • 테스트 시 인터페이스를 Mock으로 대체 가능
  • Feign 없이 Spring 공식 스택 사용

Feign과의 차이

항목 Feign HttpInterface
제공 주체 Netflix / Spring Cloud Spring Core
설정 간단 약간의 설정 필요
기반 동기 중심 WebClient 기반
미래 방향 유지 적극 권장

Spring Boot 3 이상이라면 HttpInterface가 사실상 정답이다.


결론

HttpInterface는 단순한 문법 설탕이 아니다.

  • 외부 API 호출을 선언형으로 표준화하고
  • 서비스 로직을 더 순수하게 유지하게 해준다.

외부 API 연동이 많은 서비스라면, 도입하지 않을 이유가 없다.

다음 글로 이어진다면 아래 주제가 자연스럽다.

  • 인증 헤더 / 토큰 자동 처리
  • 공통 에러 핸들링 전략
  • 테스트 및 Mocking 방법
  • Feign → HttpInterface 마이그레이션

필요하면 바로 이어서 정리한다.