API 명세 파일은 오랫동안 코드 옆에 있는 문서처럼 취급됐습니다. openapi.yaml을 고치고 Swagger UI가 보이면 끝이라고 생각하기 쉽습니다. 하지만 실제 서비스에서 API 설명은 개발자 포털, SDK 생성기, API gateway, 보안 스캐너, 테스트, 파트너 온보딩, 그리고 AI agent의 tool discovery까지 여러 소비자에게 전달됩니다. 같은 주문 API라도 내부 운영자는 debug 필드를 보고 싶고, 외부 파트너는 안정적인 공개 경로만 봐야 하며, SDK 생성기는 정확한 nullable·enum·error schema를 원합니다.

이런 차이를 복사한 OpenAPI 파일 여러 개로 관리하면, 원본 endpoint는 같은데 설명과 schema가 조금씩 갈라집니다. 반대로 모든 환경별 설명을 하나의 spec에 조건문처럼 밀어 넣으면 누가 어떤 표현을 소비하는지 알기 어렵습니다. OpenAPI Overlay는 base description에 별도의 변경 묶음을 적용해 파생 설명을 만드는 접근입니다. 중요한 흐름은 “YAML을 더 편하게 합친다”가 아니라, API 설명을 source → transform → 검증 → 배포로 다루는 구성 자산으로 바꾸는 데 있습니다.

이 글은 Contract-First API와 Source of Truth, MCP Stateless Tool Contract, API Response Compatibility Contract, Consumer-Driven Contract Testing을 OpenAPI 설명의 파생·배포 관점으로 묶습니다. OpenAPI Overlay 형식 자체는 OpenAPI Initiative의 Overlay Specification을 기준으로 확인하되, 아래 숫자는 특정 도구의 필수값이 아니라 운영을 시작할 때 쓸 수 있는 보수적 기준입니다.

이 글에서 얻는 것

  • base OpenAPI와 overlay가 각각 어떤 변경을 소유해야 하는지 구분할 수 있습니다.
  • 원본과 적용 결과(materialized spec)를 모두 검증해야 하는 이유를 이해합니다.
  • SDK, 문서, gateway, agent tool discovery가 같은 API 설명을 안전하게 소비하도록 release 경로를 설계할 수 있습니다.
  • overlay를 도입할 만한 조건과, 단일 spec을 유지하는 편이 더 나은 조건을 판단할 수 있습니다.

핵심 개념/이슈

1) API 설명의 소비자는 하나가 아니다

GET /orders/{id}라는 operation 하나도 소비자마다 필요한 정보가 다릅니다. 문서는 사람이 읽을 요약·예시·제한 사항이 중요하고, SDK 생성기는 schema의 정확한 타입과 required 여부가 중요하며, gateway는 인증·rate limit과 연결할 operation identity가 필요합니다. agent가 tool로 해석한다면 모호하지 않은 parameter 설명, 부작용 표시, 권한 경계가 더 중요해집니다.

소비자특히 중요한 정보잘못되었을 때
SDK·클라이언트 생성schema, enum, required, error response컴파일은 되지만 런타임 역직렬화·재시도 정책이 깨짐
개발자 포털·파트너공개 범위, 예시, migration 안내지원 문의와 잘못된 연동이 증가
gateway·보안 정책operationId, auth scheme, rate tier보호해야 할 경로가 빠지거나 정책이 과도하게 적용
agent/tool discoveryaction의 부작용, 입력 제약, 권한 설명read와 write를 혼동하거나 위험한 호출이 노출

여기서 base contract는 “이 operation이 존재하며 어떤 요청과 응답 의미를 가지는가”를 소유해야 합니다. path, HTTP method, operationId, 안정된 request/response schema, error semantics, 인증 방식 같은 핵심은 소비자별 overlay에서 바꾸면 안 됩니다. 이 값이 달라지면 표현 차이가 아니라 실제 API 호환성 변경입니다.

반면 환경별 문서 문구, portal용 tag 정리, beta endpoint의 노출 범위, agent에게 보여 줄 안전한 사용 예시처럼 같은 계약을 다른 문맥으로 표현하는 변경은 별도 overlay 후보가 될 수 있습니다. 경계가 흐리면 overlay가 convenience layer가 아니라 숨겨진 fork가 됩니다.

2) source가 아니라 materialized 결과가 실제 계약이다

overlay를 도입하면 repository에는 base spec과 여러 patch 파일이 생기지만, 소비자가 실제로 읽는 것은 그 조합의 결과입니다. 그래서 review에서 “overlay YAML이 작다”는 안전 근거가 될 수 없습니다. selector가 예상보다 넓은 operation을 잡거나, 적용 순서가 달라져 설명·schema·보안 요구가 바뀔 수 있기 때문입니다.

권장 파이프라인은 아래처럼 분리합니다.

base OpenAPI lint
  → overlay schema/selector validation
  → environment·consumer별 apply
  → materialized OpenAPI lint
  → semantic diff + SDK/contract test
  → digest를 붙여 portal/gateway/tool catalog 배포

최소한 PR마다 “적용 전후 operation 수, path 수, HTTP method 수, request/response schema의 breaking change 수”를 요약한 semantic diff를 남기는 편이 좋습니다. 예를 들어 문서 전용 overlay가 operationId를 삭제하거나 /v1/payments의 401 response를 감췄다면, 텍스트 diff가 작아도 중단해야 합니다. 첫 rollout에서는 base 대비 path·method·operationId가 0건 변경되는 overlay만 허용하고, schema 변경은 별도 API compatibility review로 올리는 규칙이 안전합니다.

3) transform 순서는 암묵적이면 곧 장애 원인이다

여러 overlay가 있을 때 “문서용 → 파트너용 → staging용” 순서가 코드 어디에도 고정되지 않으면 같은 commit이라도 빌드 시스템과 로컬 도구에서 결과가 달라질 수 있습니다. 이 문제는 merge conflict가 아니라 공급 경로의 비결정성입니다. 각 overlay에는 적어도 이름, 대상 consumer, 적용 순서, owner, base version 범위, 만료일 또는 재검토일을 둬야 합니다.

예를 들어 external-portal overlay가 internal operation을 숨기고, agent-catalog overlay가 write operation에 human approval 설명을 덧붙인다고 합시다. 이 둘은 통합해 한 파일로 만들 이유가 없습니다. 그러나 agent-catalog 결과를 다시 external-portal에 적용하는 식의 암묵적 체인은 피해야 합니다. 각 결과는 공통 base에서 독립적으로 materialize하고, artifact 이름도 orders-api@base-sha+agent-catalog-sha처럼 추적 가능하게 만드는 편이 낫습니다.

실무 적용

1) 복제 파일부터 없애지 말고 변형 사유를 inventory한다

처음에는 저장소와 portal, gateway 설정에 있는 OpenAPI 변형본을 10개 이하로 골라 표로 정리합니다. 각 파일이 base와 다른 부분을 “제품 계약”, “문서·표현”, “환경 endpoint”, “보안·배포 정책”, “임시 workaround”로 분류합니다. 이 작업에서 product contract가 이미 갈라져 있음을 발견하면 overlay로 덮지 말고 API version·deprecation·consumer migration 문제로 올려야 합니다.

overlay로 시작하기 좋은 사례는 다음과 같습니다.

  • 같은 공개 operation에 대해 내부/외부 portal의 설명·예시·tag만 다르다.
  • beta operation을 특정 partner catalog에만 보이게 하되 request/response 의미는 base와 같다.
  • agent tool catalog에 write action의 영향, 승인 필요 여부, pagination 제한을 보강한다.

반대로 operation의 path, 인증 requirement, request field 의미, 응답 enum이 환경마다 다르면 overlay가 아니라 별도 API 계약입니다. “staging에서만 field가 하나 더 있다”는 편의는 SDK·테스트·agent 행동을 엇갈리게 만들므로 base를 version으로 관리하거나 server behavior를 정렬해야 합니다.

2) 파생 spec을 build artifact처럼 버전·서명·배포한다

CI에서 각 materialized spec을 생성한 뒤 lint 결과와 semantic diff를 함께 저장합니다. production portal, gateway, tool catalog이 그 파일을 가져간다면, Git branch 이름 대신 immutable artifact digest를 release record에 남기는 편이 좋습니다. 그래야 “문서는 새 endpoint를 보이는데 gateway는 아직 막는다” 또는 “agent는 오래된 parameter를 보았다”는 문제를 재현할 수 있습니다.

가벼운 시작 기준은 세 가지입니다.

  1. base와 overlay의 commit SHA를 artifact metadata에 기록한다.
  2. materialized spec의 SHA-256을 portal·gateway·tool catalog release에 기록한다.
  3. 배포 뒤 endpoint 5개 이하를 골라 문서, SDK smoke test, gateway route, tool schema가 같은 operationId와 parameter를 보는지 canary로 대조한다.

새 layer를 도입하는 만큼 빌드 시간이 늘 수 있습니다. 그래서 consumer별 spec이 3개라면 전체 API를 매번 무겁게 생성하기보다, 변경한 operation과 그 schema dependency에 대한 빠른 validation을 PR에서 하고 전체 materialization은 main merge 뒤 한 번 수행하는 식으로 나눌 수 있습니다. 단, production publish 직전에는 반드시 전체 결과를 다시 만들어 digest를 확정해야 합니다.

3) agent 소비자는 사람이 읽는 문서보다 더 엄격하게 제한한다

API 설명이 AI agent의 tool schema로 사용되면, summary를 그럴듯하게 쓰는 것만으로 충분하지 않습니다. DELETE /accounts/{id}가 실제로 외부 효과를 내는지, 어떤 role과 승인 reference가 필요한지, 되돌릴 수 있는지, 어떤 parameter가 scope를 넓히는지를 구조화해 전달해야 합니다. overlay는 이때 agent에 필요한 안전 문맥을 보강하는 데 쓸 수 있지만, runtime 인가를 대체하지는 못합니다.

예를 들어 tool catalog용 파생 spec에 x-risk-tier: high, x-approval-required: true, x-effect: external-delete 같은 조직 extension을 붙일 수 있습니다. 그러나 서버가 그 extension을 믿고 authorization을 생략하면 안 됩니다. MCP OAuth의 리소스·도구별 권한 위임처럼 실제 요청에서는 scope, audience, parameter policy, 승인 증적을 별도로 검증해야 합니다. API description은 결정에 필요한 문맥이고, policy engine은 결정을 강제하는 경계입니다.

4) change budget으로 overlay 확산을 제한한다

overlay가 유용하다는 이유로 팀마다 하나씩 만들면 base보다 관리 대상이 더 많아집니다. 운영 초기에 overlay 수를 API domain당 2~4개로 제한하고, 새 overlay는 기존 것을 합칠 수 없는 이유와 owner를 review하도록 두는 편이 좋습니다. 90일 이상 변경이 없거나 대상 consumer가 사라진 overlay는 제거 후보로 올립니다.

또한 한 release에서 base schema와 overlay selector와 gateway policy를 동시에 크게 바꾸지 마세요. 원인 분리가 불가능해집니다. 아래 우선순위가 안정적입니다.

  1. base contract의 breaking/non-breaking change를 먼저 판정한다.
  2. overlay를 적용한 materialized diff가 의도와 같은지 확인한다.
  3. SDK·consumer contract test를 통과시킨다.
  4. gateway·portal·tool catalog에 canary로 배포한다.
  5. 실제 consumer 오류율과 unknown operation 비율을 확인한 뒤 확대한다.

트레이드오프/주의점

  1. Overlay는 API versioning의 대체재가 아니다. request/response 의미가 달라졌다면 파생 설명으로 감추지 말고 호환성 정책, version, deprecation window를 써야 한다.
  2. 적용 도구의 지원 수준이 균일하지 않다. lint, portal, SDK generator, gateway가 같은 Overlay 기능을 직접 이해한다고 가정하지 말고, materialized OpenAPI를 공통 입력으로 삼는다.
  3. 문서 가시성과 서버 권한은 다른 문제다. operation을 portal에서 숨겨도 endpoint가 보호되는 것은 아니다. routing, authentication, authorization, audit는 runtime에서 강제한다.
  4. selector가 강력할수록 blast radius가 커진다. 넓은 target이나 wildcard는 새 operation이 추가됐을 때 의도하지 않은 patch를 받을 수 있다. operationId 기반의 좁은 selector와 diff 검증을 우선한다.
  5. 모든 API에 필요하지 않다. 단일 팀, 단일 portal, SDK 하나만 있는 안정된 API라면 base spec 한 개와 간단한 문서 생성 흐름이 유지보수 비용이 더 낮다.

체크리스트 또는 연습

운영 체크리스트

  • base contract가 path·method·operationId·schema·error semantics의 단일 owner다.
  • overlay마다 대상 consumer, owner, 적용 순서, base 범위, 재검토일이 있다.
  • CI가 overlay apply 후의 materialized spec을 다시 lint하고 semantic diff를 보관한다.
  • 문서 전용 overlay는 path·HTTP method·operationId·보안 requirement를 변경하면 실패한다.
  • SDK, gateway, portal, tool catalog release가 같은 materialized spec digest를 기록하거나 대조한다.
  • agent 노출 operation에는 risk tier·권한·부작용 문맥이 있으며, 실제 runtime policy와 충돌하지 않는다.
  • 오래된 overlay와 임시 workaround를 분기별로 제거·통합한다.

연습

하나의 주문 API를 골라 base OpenAPI, external portal, internal portal, agent tool catalog의 차이를 표로 적어 보세요. 그 차이를 계약 변경과 표현 변경으로 나눈 뒤, 표현 변경 하나만 overlay로 만듭니다. 적용 전후에 path·method·operationId·schema가 모두 같다는 semantic diff를 생성하고, portal·SDK·gateway가 같은 artifact digest를 사용했는지 확인하는 release check를 설계해 보세요. 이 세 결과를 연결하지 못한다면, overlay는 파일 분리일 뿐 운영 가능한 API 설명 체계가 아닙니다.

관련 글