본문으로 건너뛰기
ElastiCORE 3.0 은 릴리스 후보(RC)입니다: Maven Central 의 3.0.261022-rc1. 2.2 라인 프로젝트는 2.2 문서를 보세요.
버전: 3.0

HTTP 포트

model/port.yml
port:
ExternalApiService:
meta: http @url("https://api.example.com") @auth("Bearer token")
methods:
getUser:
meta: method @get("/api/users/{userId}")
params:
userId: long
return: UserDTO

createUser:
meta: method @post("/api/users")
params:
body: UserRequest @body
return: UserResponse

updateUser:
meta: method @HttpEndpoint(url="/api/users/{id}", method="PUT")
params:
id: long
body: UserRequest @body
return: UserResponse
위치어노테이션뜻
포트@url("baseUrl")서버의 기본 URL
포트@auth("token")기본 Authorization 헤더
포트@timeout(connect=.., read=.., write=.., response=..)타임아웃(ms, 기본 10000 / 90000 / 90000 / 60000)
메서드@get, @post, @put, @delete("/path")메서드와 경로
메서드@HttpEndpoint(url=, method=, contentType=)상세 형식 (PATCH 포함)
파라미터@body요청 본문. URL 의 {이름} 은 경로 변수, 그 밖은 쿼리 파라미터

런타임 속성​

포트마다 application.yml 의 {domainName}.{PortServiceName}.{속성} 이 DSL 을 덮어씁니다 - 예를 들어 erp.CreditCheckPort.url, .connectTimeout, .readTimeout, .authKey, .apiKey. 전역 기본값은 elasticore.http.connectTimeout, .readTimeout 입니다. 프록시, SSL, multipart form-data 는 포트 가이드 (blueprint/elasticore-dsl-port-guide.md)에 있습니다.

두 가지 클라이언트​

런타임 프록시 (기본)httpPort: spring (Spring Boot 4)
생성물@ExternalService 인터페이스Spring @HttpExchange 인터페이스 + @ImportHttpServices 의 <Domain>HttpServices + 기본값 properties 파일
등록@EnableElastiCoreSpring
base URL호출할 때마다 읽음({id}.url)애플리케이션이 뜰 때 한 번 정해짐
env.yml
elasticore:
config:
httpPort: spring # 이 도메인의 HTTP 포트를 Spring HTTP 서비스 클라이언트로
implementation 'org.springframework.boot:spring-boot-starter-restclient'
CreditCheckPort.java (httpPort: spring 으로 생성)
@HttpExchange
public interface CreditCheckPort {

@GetExchange(url = "/partners/{bizNo}/credit")
CreditResultDTO checkCredit(@PathVariable("bizNo") String bizNo);

@PostExchange(url = "/partners/{bizNo}/review")
CreditResultDTO requestReview(@PathVariable("bizNo") String bizNo, @RequestBody(required = false) CreditResultDTO body);
}

그룹 이름은 <도메인>--<포트>(erp--credit-check-port)입니다. 예전 키는 그대로 통하고, Boot 4 키는 spring.http.serviceclient.erp--credit-check-port.base-url 등입니다. Spring Boot 3 에서 켜면 경고하고 런타임 프록시로 생성합니다. 몇몇 모양(form-urlencoded, @contentType 없는 multipart, 배열 파라미터 ...)은 런타임 방식으로 남고, 빌드 로그가 이유를 말합니다.

상대가 실패했을 때​

포트는 실패를 판단하지 않습니다. 두 방식 모두 오류 응답의 본문을 반환값으로 돌려줍니다:

상대가런타임 프록시httpPort: spring
200, 읽을 수 있는 본문반환값반환값
4xx/5xx, JSON 본문반환값 (없는 필드는 null)반환값
4xx/5xx, 반환 타입으로 읽을 수 없는 본문예외예외
답이 없음 - 연결 거부, 시간 초과예외 (WebClientRequestException 등)RestClientException

순진하게 쓰면 틀린 채로 성공합니다: 택배사가 500 을 답해도 운송장 번호가 null 인 채 주문이 "배송됨" 으로 저장되고 200 이 나갑니다. 포트를 부르는 코드가 판단하고 io.elasticore.springboot3.http.PortCallException 을 던지면, 생성된 XxxApiErrors 가 502, "code": "upstream" 으로 답합니다:

PurchaseOrderService (내 것) - 배송 명령이 택배사를 부른다
@Override
@Transactional // 상태 변경과 호출을 한 트랜잭션으로: 실패하면 함께 되돌림
public PurchaseOrderDTO ship(String orderId) {
PurchaseOrderDTO shipped = super.ship(orderId);
ShipmentReply reply;
try {
reply = courier.ship(new ShipmentRequest(orderId));
} catch (RestClientException unreachable) { // 런타임 프록시면 WebClientException 도
throw new PortCallException("The courier could not be reached", unreachable);
}
if (reply == null || reply.getTrackingNo() == null) { // 오류 상태도 값으로 오므로 내용으로 판단
throw new PortCallException("The courier did not accept the shipment");
}
...
}

PortCallException 은 unchecked 라 트랜잭션 안에서 던지면 그 메서드가 바꾼 것이 되돌려집니다. 메시지 코드를 주면 번역되고(PortCallException(code, message, args...)), 상대의 상태와 본문을 남기려면 PortCallException(port, upstreamStatus, upstreamBody, message, cause). 설정으로 켜는 실패 정책은 아직 없습니다.

가짜 상대로 테스트하기​

  • 포트를 목으로 바꿉니다: @MockitoBean CourierApiPort courier;(Spring Boot 3.4 이상, 이전은 @MockBean). 성공, 오류 본문(null 필드), 예외를 각각 돌려주게 해서 502 와 되돌림을 확인합니다.
  • 같은 서버 안의 가짜 컨트롤러(/fake-courier)를 부르게 하려면 고정 포트로 띄웁니다(webEnvironment = DEFINED_PORT): httpPort: spring 과 RANDOM_PORT 를 같이 쓰면 포트 0 을 부릅니다.
  • 바깥의 가짜 서버(MockWebServer, WireMock)는 그 주소를 {domain}.{Port}.url 에 넣습니다.