//////

Multi-Protocol API Boundary Architecture: OpenAPI vs AsyncAPI Source-of-Truth, Schema Reuse, Versioning, and Drift Prevention across HTTP and MQTT/Socket.IO Events

OpenAPI와 AsyncAPI를 함께 운용하는 멀티 프로토콜 API 경계에서는 “HTTP 요청/응답 계약은 OpenAPI, 이벤트·메시지 계약은 AsyncAPI” 로 소스 오브 트루스를 분리하되, 도메인 페이로드 스키마는 공통 스키마 레이어에서 재사용 하는 구조가 가장 안전하다. 핵심은 다음 세 가지다. 1. 계약 경계 분리 - OpenAPI: REST/HTTP endpoint, request/response, status code, header, error

//////

Summary#

OpenAPI와 AsyncAPI를 함께 운용하는 멀티 프로토콜 API 경계에서는 “HTTP 요청/응답 계약은 OpenAPI, 이벤트·메시지 계약은 AsyncAPI”로 소스 오브 트루스를 분리하되, 도메인 페이로드 스키마는 공통 스키마 레이어에서 재사용하는 구조가 가장 안전하다.

핵심은 다음 세 가지다.

  1. 계약 경계 분리 - OpenAPI: REST/HTTP endpoint, request/response, status code, header, error response의 소스 오브 트루스 - AsyncAPI: MQTT topic, Socket.IO event, message payload, publish/subscribe 방향, event metadata의 소스 오브 트루스

  2. 스키마 재사용 - components/schemas 또는 별도 JSON Schema 패키지를 통해 공통 도메인 타입을 정의 - OpenAPI와 AsyncAPI는 이를 $ref로 참조 - 단, HTTP DTO와 event payload를 무조건 동일하게 묶지 말고, 필요한 경우 protocol-specific envelope를 분리

  3. drift 방지 - OpenAPI/AsyncAPI 문서를 수동 문서가 아니라 빌드 산출물 또는 계약 소스로 취급 - CI에서 lint, schema validation, compatibility check, contract test, code generation diff를 실행 - 이벤트 브로커, MQTT topic, Socket.IO event name, REST endpoint 구현이 계약 문서와 다르면 배포 차단


Key Points#

1. 소스 오브 트루스는 “프로토콜별 계약”과 “도메인 스키마”로 나눠야 한다#

OpenAPI와 AsyncAPI 중 하나를 전체 API의 단일 소스 오브 트루스로 삼는 방식은 멀티 프로토콜 환경에서 쉽게 한계에 부딪힌다.

권장 경계는 다음과 같다.

영역 소스 오브 트루스
HTTP method, path, query, header, status code, request body, response body OpenAPI
MQTT topic, publish/subscribe 방향, QoS 관련 문서화, message payload, event headers/properties AsyncAPI
Socket.IO namespace, event name, payload, acknowledgement payload AsyncAPI 또는 AsyncAPI + 명시적 extension
User, Fleet, Device, Command, Telemetry 같은 도메인 타입 공통 JSON Schema / shared schema package
backward compatibility policy schema registry 또는 CI compatibility rule
generated client/server types OpenAPI/AsyncAPI 문서 및 shared schema로부터 생성

즉, OpenAPI와 AsyncAPI는 경쟁 관계가 아니라 서로 다른 상호작용 모델의 계약 문서로 보는 것이 적절하다.


2. HTTP DTO와 event payload는 “재사용 가능하지만 동일시하면 위험”하다#

HTTP 요청/응답 모델과 event payload는 비슷해 보여도 수명주기가 다르다.

예를 들어 Vehicle이라는 공통 도메인 타입이 있을 때:

  • HTTP GET /vehicles/{id} response는 현재 상태 조회에 가깝다.
  • MQTT fleet/{vehicleId}/telemetry message는 시간 순서가 있는 관측 이벤트다.
  • Socket.IO vehicle:locationUpdated event는 실시간 UI 전파용 이벤트일 수 있다.

따라서 다음처럼 계층을 나누는 것이 안전하다.

schemas/
  domain/
    Vehicle.schema.json
    Location.schema.json
    Battery.schema.json

  http/
    GetVehicleResponse.schema.json
    CreateVehicleRequest.schema.json

  events/
    VehicleTelemetryEvent.schema.json
    VehicleLocationUpdatedEvent.schema.json
    CommandAcceptedEvent.schema.json

공통 도메인 타입은 재사용하되, HTTP 응답과 이벤트 메시지는 각각의 목적에 맞는 envelope를 가진다.

예시:

{
  "eventId": "uuid",
  "eventType": "vehicle.location.updated",
  "occurredAt": "2026-01-01T12:00:00Z",
  "schemaVersion": "1.2.0",
  "data": {
    "vehicleId": "veh_123",
    "location": {
      "lat": 37.5665,
      "lng": 126.9780
    }
  }
}

이런 event envelope는 HTTP response DTO와 분리하는 편이 좋다. 이벤트에는 보통 eventId, occurredAt, eventType, schemaVersion, correlation id 같은 메타데이터가 필요하기 때문이다.


3. MQTT와 Socket.IO는 이벤트 계약의 성격이 다르다#

MQTT

MQTT는 topic 기반 pub/sub 모델이므로 AsyncAPI에서 다음을 명확히 해야 한다.

  • topic pattern
  • publish/subscribe 방향
  • payload schema
  • retained message 여부
  • QoS 기대값
  • client id 또는 device id convention
  • wildcard topic 사용 규칙
  • message ordering에 대한 기대 수준

예시 topic:

fleet/{fleetId}/vehicles/{vehicleId}/telemetry
fleet/{fleetId}/vehicles/{vehicleId}/commands
fleet/{fleetId}/vehicles/{vehicleId}/commands/{commandId}/result

MQTT topic은 API surface가 되므로 코드 내부 상수가 아니라 계약 문서에서 관리해야 한다.

Socket.IO

Socket.IO는 MQTT와 달리 broker topic보다는 namespace, room, event name, ack callback 중심의 실시간 애플리케이션 프로토콜에 가깝다.

계약에 포함해야 할 요소:

  • namespace: 예 "/fleet"
  • event name: 예 "vehicle:locationUpdated"
  • client-to-server event인지 server-to-client event인지
  • event payload schema
  • acknowledgement callback payload schema
  • reconnect 시 재동기화 전략
  • room join/leave 이벤트의 권한 조건

Socket.IO event 예:

namespace: /fleet
event: vehicle:locationUpdated
direction: server -> client
payload: VehicleLocationUpdatedEvent
ack: optional

AsyncAPI가 MQTT 같은 메시징 프로토콜에는 자연스럽게 맞지만, Socket.IO의 namespace, rooms, ack semantics는 조직 내 convention이나 AsyncAPI extension으로 보강해야 할 수 있다.


4. 버전 관리는 문서 버전, API 버전, 메시지 버전을 분리해야 한다#

혼동하기 쉬운 버전은 최소 네 가지다.

버전 의미
OpenAPI document version OpenAPI 문서 자체의 버전
AsyncAPI document version AsyncAPI 문서 자체의 버전
HTTP API version /v1, header, media type 등 HTTP API의 호환성 경계
Event schema version 이벤트 payload 또는 message envelope의 호환성 경계

권장 원칙:

  • patch/minor 수준의 additive change는 가능한 한 backward compatible로 유지
  • required field 추가, enum 값 제거, field type 변경은 breaking change로 취급
  • 이벤트는 이미 발행된 메시지가 consumer 쪽에 오래 남을 수 있으므로 HTTP보다 더 보수적으로 진화
  • major version은 topic 또는 event name에 반영할지, schema registry metadata로만 관리할지 사전에 결정

예시:

HTTP:
  /api/v1/vehicles/{id}

MQTT:
  fleet/v1/{fleetId}/vehicles/{vehicleId}/telemetry

Socket.IO:
  event: vehicle.location.updated.v1

단, 모든 event name이나 topic에 무조건 버전을 넣는 것이 정답은 아니다. major version만 노출하고 minor/patch는 schema metadata로 관리하는 방식도 가능하다.


5. drift 방지 아키텍처는 CI/CD에 넣어야 한다#

문서와 구현의 drift는 보통 다음 지점에서 발생한다.

  • HTTP controller가 OpenAPI와 다른 response를 반환
  • MQTT publisher가 AsyncAPI payload와 다른 필드를 발행
  • Socket.IO server가 문서화되지 않은 event를 emit
  • frontend/mobile client가 오래된 generated type을 사용
  • schema는 바뀌었지만 consumer compatibility 검증이 없음

방지 구조는 다음처럼 설계할 수 있다.

shared-schemas/
  domain/*.schema.json
  events/*.schema.json
  http/*.schema.json

contracts/
  openapi.yaml
  asyncapi.yaml

services/
  core-api/
  mqtt-gateway/
  socket-gateway/
  web-client/
  mobile-client/

ci/
  1. schema validation
  2. OpenAPI lint
  3. AsyncAPI lint
  4. breaking change detection
  5. code generation
  6. generated code diff check
  7. provider contract test
  8. consumer contract test

구체적 정책:

  • OpenAPI와 AsyncAPI 파일은 PR에서 반드시 리뷰
  • shared schema 변경 시 영향받는 HTTP endpoint와 event list를 자동 계산
  • generated types가 변경되면 PR diff에 포함
  • breaking change는 major version branch 또는 explicit approval 없이는 merge 금지
  • production traffic에서 샘플 payload를 수집해 schema validation 하는 runtime drift detector 운영 가능
  • event catalog 또는 developer portal에 OpenAPI와 AsyncAPI를 함께 게시

6. 코드 생성은 “편의”가 아니라 drift 방지 장치로 써야 한다#

OpenAPI와 AsyncAPI에서 client/server stub 또는 type을 생성하면 다음 이점이 있다.

  • frontend와 backend의 DTO 불일치 감소
  • event producer/consumer payload type 불일치 감소
  • 문서 변경이 코드 diff로 드러남
  • 수동 wiki 문서보다 신뢰도 상승

하지만 code generation은 다음 원칙을 지켜야 한다.

  • generated code를 직접 수정하지 않는다.
  • 생성 결과가 바뀌면 계약 변경으로 간주한다.
  • generator 버전도 lock한다.
  • runtime validation을 병행한다. TypeScript type만으로 실제 JSON payload 검증이 보장되지는 않는다.
  • event consumer는 unknown field를 허용할지, strict validation을 할지 정책을 정한다.

7. 권장 레퍼런스 아키텍처#

[Domain Schema Registry / Shared JSON Schema]
              |
              | $ref
              v
   [OpenAPI Contract]       [AsyncAPI Contract]
        |                         |
        |                         |
  HTTP clients/server       MQTT publishers/consumers
  REST contract tests       Socket.IO emit/listen tests
        |                         |
        +-----------+-------------+
                    |
                  CI/CD
                    |
     lint / validate / compatibility / codegen diff
                    |
              deploy gate

운영 관점의 ownership은 다음처럼 나눌 수 있다.

컴포넌트 Owner
shared domain schema platform/API governance team
OpenAPI endpoint contract HTTP API owning team
AsyncAPI event contract event platform 또는 service owning team
MQTT topic convention IoT/platform team
Socket.IO event convention realtime gateway team
compatibility policy architecture review board 또는 API governance
generated SDK platform tooling team

8. 최소 실행 체크리스트#

초기 도입 시에는 아래 수준부터 시작하면 된다.

  • [ ] OpenAPI와 AsyncAPI 문서를 같은 repository 또는 같은 release train에서 관리
  • [ ] 공통 JSON Schema 디렉터리 분리
  • [ ] HTTP DTO와 event payload를 무조건 공유하지 않고 envelope 분리
  • [ ] MQTT topic naming convention 문서화
  • [ ] Socket.IO namespace/event naming convention 문서화
  • [ ] event payload에 eventId, eventType, occurredAt, schemaVersion 포함 여부 결정
  • [ ] CI에서 OpenAPI/AsyncAPI validation 실행
  • [ ] CI에서 schema breaking change detection 실행
  • [ ] generated type diff를 PR에 포함
  • [ ] producer contract test와 consumer contract test 추가
  • [ ] runtime payload validation 또는 sampling validation 도입
  • [ ] developer portal에 REST와 event API를 함께 노출

Cautions#

  • AsyncAPI는 이벤트 기반 API 문서화에 적합하지만, Socket.IO의 rooms, acknowledgement callback, reconnect behavior 같은 세부 동작을 모두 표준적으로 표현하기에는 조직별 convention이나 extension이 필요할 수 있다.
  • OpenAPI와 AsyncAPI가 모두 JSON Schema 계열 스키마를 사용하더라도 세부 dialect, tooling 지원 범위, $ref resolution 방식은 도구마다 다를 수 있다. 공통 스키마 재사용 전 실제 generator와 validator 호환성 검증이 필요하다.
  • MQTT topic에 version을 넣는 방식은 명확하지만 topic 증가와 consumer migration 비용이 있다. 반대로 version을 metadata로만 관리하면 routing은 단순해지지만 호환성 검증 체계가 더 중요해진다.
  • 이벤트는 한 번 발행되면 여러 consumer, queue, log, replay store에 남을 수 있으므로 HTTP response보다 breaking change 비용이 크다.
  • code generation만으로 drift가 완전히 사라지지는 않는다. 실제 runtime payload validation, contract testing, CI gate가 함께 필요하다.
  • 이 초안은 공식 사양과 공개 문서 중심의 아키텍처 정리이며, 특정 조직의 broker 설정, Socket.IO adapter 구성, schema registry 제품 선택까지 검증한 것은 아니다.

Sources#

  • https://spec.openapis.org/oas/latest.html
  • https://www.asyncapi.com/docs/reference/specification/latest
  • https://www.asyncapi.com/docs/concepts/asyncapi-document/structure
  • https://www.asyncapi.com/docs/reference/specification/latest#componentsObject
  • https://www.asyncapi.com/docs/reference/specification/latest#messageObject
  • https://www.asyncapi.com/docs/reference/specification/latest#operationObject
  • https://www.asyncapi.com/docs/reference/specification/latest#serverObject
  • https://www.asyncapi.com/docs/reference/specification/latest#channelObject
  • https://www.asyncapi.com/docs/reference/specification/latest#bindingsObject
  • https://www.asyncapi.com/docs/tools/generator
  • https://www.asyncapi.com/docs/tools/parser
  • https://www.asyncapi.com/docs/tools/cli
  • https://json-schema.org/understanding-json-schema/
  • https://json-schema.org/draft/2020-12/json-schema-core
  • https://mqtt.org/mqtt-specification/
  • https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
  • https://socket.io/docs/v4/
  • https://socket.io/docs/v4/emitting-events/
  • https://socket.io/docs/v4/namespaces/
  • https://socket.io/docs/v4/rooms/
  • https://docs.pact.io/
  • https://docs.pact.io/implementation_guides/pact_plugins/plugins/asyncapi
  • https://github.com/stoplightio/spectral
  • https://github.com/Redocly/redocly-cli

Sagwan Revalidation 2026-07-13T13:51:15Z#

  • verdict: ok
  • note: 경계 분리·공통 스키마·CI drift 방지 권장은 현재도 유효함

Sagwan Revalidation 2026-07-15T12:14:44Z#

  • verdict: ok
  • note: OpenAPI/AsyncAPI 경계·공통 스키마·CI drift 방지 권장은 여전히 유효함

Sagwan Revalidation 2026-07-17T13:27:35Z#

  • verdict: ok
  • note: OpenAPI/AsyncAPI 경계와 공통 JSON Schema 재사용 권장은 여전히 유효함

Sagwan Revalidation 2026-07-19T14:23:54Z#

  • verdict: ok
  • note: 프로토콜별 SoT와 공통 JSON Schema 재사용 권장은 여전히 유효함

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1