콘텐츠로 이동

HTTP Client — 공통 스펙

스펙 목차 | 이전: Channel 메시징 | 다음: SPOT 메시징

이 문서는 HTTP client를 Framework에서 등록하고 호출하는 경계를 정의한다. 정체성, fluent builder 형식, 실행 terminator, Spot 실행 문맥과의 결합, codec과 공통 오류 model을 소유한다.

상세 계약(builder, 응답, redirect·retry·cookie, 인증·TLS·proxy, 압축, 오류 매핑, 회귀)은 같은 폴더의 01~11이 각각 소유한다.

공통 개념의 언어별 이름은 language-interfaces가 소유하고, 그 이름의 정확한 parameter·return type은 languages/<lang>/이 투영해 소유한다.

1. 정체성 — framework 동반 client

HTTP client는 STREAM connector와 같은 자리에 있다. 별도 패키지로 배포하지만 framework 전용 동반 client이며, 계약은 framework가 소유한다.

STREAM connector HTTP client
패키지 별도 별도
계약 소유 framework 공통 스펙(32) framework 공통 스펙(이 문서)
언어별 인터페이스 stream-connector/languages/<lang>/ http-client/languages/<lang>/

존재 이유는 하나다 — framework application이 외부 API와 레거시 API를 zlink 스타일로 호출할 수 있어야 한다. 범용 HTTP 라이브러리를 대체하려는 것이 아니다.

HTTP client가 소비하는 Framework 계약과 언어별 산출물 경계는 01 범위와 아키텍처 §1.3가 소유한다. Spot 실행 문맥과의 결합은 §3.2의 execution scheduler 주입점으로 표현한다.

2. Fluent builder

framework messaging과 같은 형식이다 — "operation 선택 → 설정 → 실행 방식 terminator".

client.post("/games")               // operation
      .header("x-request-id", ...)  // 설정
      .query("region", "kr")
      .body(createGameReq)
      .timeout(3s)
      .submit<CreateGameRes>()      // response completion terminator — Java·Node 이름.
                                    // 언어별 이름은 언어별 인터페이스 §1.4
  • verb 7종: get / post / put / delete / patch / head / options.
  • 설정 축: header, query, timeout, body 소스(typed / raw / streaming / form / multipart).
  • body 소스는 상호 배타다. 섞으면 ProtocolError.

builder의 세부 계약(path 형식, percent-encoding, body 소스별 retry 가능 여부 등)은 03 Request builder가 소유한다.

3. 실행 terminator — response completion (+ callback)

HTTP client의 완료 표면은 response completion, callback, 그리고 DI server builder의 Yield다. 종결자의 이름·응답 형태·one-way의 부재는 언어별 인터페이스 §1.4가 소유한다.

실행 방식 무엇을 기다리나 Spot 실행 줄
response completion HTTP response가 도착할 때까지 기다린다 현재 turn을 유지한다
Yield (DI server builder) HTTP response가 도착할 때까지 기다린다 gate 반납과 재개의 의미는 Submit과 완료 §2를 따른다

Callback은 awaitable을 사용하지 않는 호출자(CLI, 이벤트 루프 기반 client)를 위한 별도 완료 경로다. HTTP client는 그 경로도 함께 제공한다.

Spot 실행 문맥에서 callback을 사용하면 호출은 기다리지 않고 그대로 진행하며, 완료 callback은 그 Spot 실행 줄의 새 turn으로 큐에 들어간다. 완료 값으로 같은 turn의 판단을 이어가야 하면 callback 대신 언어별 response completion terminator를 사용한다.

3.1 외부 HTTP를 기다리면서 Spot gate를 반납하는 방법

Yield가 있는 실행 문맥은 Submit과 완료 §2가, DI server builder의 Yield와 I/O Worker + Worker Yield의 두 사용 형태와 예제는 05 §5.2가 소유한다. HTTP package는 Spot execution context를 판정하지 않는다. Framework는 DI 시 현재 execution turn을 주입하고, DI server builder의 Yield는 그 turn을 반납한다(turn seam).

3.2 turn seam — 주입점 하나

HTTP client는 framework error kind와 codec에 의존하며 Spot turn 정보를 보유하지 않는다. Framework는 DI 시 주입한 execution scheduler 하나에 현재 turn을 연결한다.

  • HTTP client는 execution scheduler 주입점을 공개 계약으로 둔다. scheduler는 completion을 어디서 재개할지 정한다.
  • Framework는 DI 등록 시 callback completion scheduler를 주입한다. Callback은 원래 Spot 실행 줄의 새 turn으로 들어간다.
  • DI server builder의 Yield는 주입된 turn을 반납하고 같은 실행 줄의 새 turn에서 재개한다.

C++ HTTP client는 같은 scheduler seam을 coroutines(resume_scheduler)와 framework_resume_scheduler_t로 표현한다.

3.3 runtime 실행 문맥은 blocking terminator 호출을 거부한다

완료 값을 동기로 언래핑하는 public 종결자의 언어별 제공 여부와 이름은 언어별 인터페이스 §1.4가 소유한다. runtime 실행 문맥에서 blocking 종결자를 호출하면 Submit과 완료 §2에 따라 InvalidOperation으로 즉시 실패한다. blocking 종결자가 없는 언어에서 테스트나 CLI가 동기로 기다려야 하면 호출자가 언어 관용(GetAwaiter().GetResult(), runBlocking, .join())으로 직접 감싼다.

4. 서버 표면과 등록

서버(Spot handler·channel handler)에서 사용하는 HTTP client는 DI로 주입받는다. 정적 팩토리로 handler 안에서 client를 만들지 않는다 — 연결 pool과 turn seam을 잃는다.

  • application이 명명 등록한다. baseUrl, 인증, timeout, retry 정책은 서비스마다 다르므로 framework가 기본 client 하나를 자동 등록하지 않는다.
  • 등록 표면의 형태는 channel 등록과 같다: 구성 단계에서 이름과 정책을 함께 등록하고, handler는 그 이름으로 주입받는다.
  • 정적 팩토리 진입점은 client-side 전용으로 남긴다. CLI와 client 시나리오가 사용한다.
표면 누가 쓰나 terminator
정적 팩토리 CLI · client 시나리오 response completion / callback
DI 주입 client Spot handler · 서버 코드 response completion / callback / Yield

5. Codec

HTTP client는 framework와 codec extension을 공유하지만 registry 인스턴스는 따로 가진다 (Stream Session §5). 같은 codec extension 객체를 양쪽에 각각 등록할 수 있으나, 등록은 host마다 따로 해야 한다.

typed body의 encode/decode는 그 registry가 담당한다. raw body API는 registry를 거치지 않는다.

6. 오류 모델

HTTP client는 자체 예외 계층을 만들지 않는다. framework 공용 오류 모델 (Framework 오류 모델)의 error kind를 그대로 사용한다. HTTP client 전용 error kind를 새로 만들지 않는다.

상황 kind
구성·사용 오류, typed decode, 압축 해제 또는 redirect 형식 오류 ProtocolError
Network, DNS, proxy와 target 연결 실패 Unavailable
설정한 response body byte 제한 초과 Rejected
시도당 timeout 초과 DeadlineExceeded
HTTP status가 400 이상이거나 분류할 수 없는 실행 실패 InternalFailure

세부 매핑은 09 오류 모델이 소유한다.

7. 회귀 테스트

항목 검증
terminator 축 언어별 공개 표면의 종결자가 언어별 인터페이스 §1.4 표와 정확히 같다 — 표에 없는 이름이 없고, 표의 이름이 빠지지 않았다
turn 유지 Spot handler가 response completion을 기다리는 동안 같은 Spot의 다른 callback이 시작하지 않는다
turn 반납 server builder의 Yield와 RunIoWorker + Worker Yield만 shared Spot gate를 반납한다. response completion은 반납하지 않는다
표면 제한 standalone HTTP request builder에는 Yield가 없고, C++ blocking 종결자는 runtime 실행 문맥에서 InvalidOperation으로 실패한다
등록 서버 표면이 DI 주입으로만 얻어지고, handler 안에서 정적 팩토리로 client를 만들지 않는다
오류 kind HTTP client 전용 kind가 없고 framework 공용 kind만 사용한다
builder body 소스를 섞으면 ProtocolError로 실패한다