OpenAPI differ가 아무도 깨뜨리지 않은 'breaking change'를 플래그한 이유 — 응답 측에서 enum이 축소된 경우
요약
OpenAPI 스펙 비교 도구를 개발하여 API 변경 로그를 자동 생성했습니다. 이 과정에서 응답(Response) 측의 enum 축소 같은 '텍스트적 차이'가 실제로는 breaking change가 아닐 수 있음을 발견했습니다. 이는 스키마가 어느 경계에 위치하는지에 따라 'breaking-ness'의 방향성이 달라짐을 시사합니다.
핵심 포인트
- 응답(Response) 측 enum 축소는 클라이언트 컴파일에 영향을 주지 않아 breaking이 아닐 수 있다.
- Request schema 변경은 구형 클라이언트가 거부되는 페이로드를 보내게 하므로 항상 breaking이다.
- OpenAPI 스펙 비교 시, 단순한 텍스트 차이가 아닌 의미적(Semantic) 비교가 필수적이다.
- 스펙을 정규화(normalize)하는 과정이 포함되어야 가짜 diff를 방지할 수 있다.
저는 API 릴리스 노트를 작성하는 것이 오후 시간을 잡아먹기 때문에 OpenAPI 변경 로그 생성기를 만들었습니다. 두 스펙을 비교하고, 구조화된 breaking changes 목록을 출력하며, LLM(대규모 언어 모델)의 재작성 이력은 없습니다. 처음으로 실제 테스트를 진행해 보니 — 제 자신의 API v3 스펙과 v2를 비교하는 것 — 정확히 하나의 breaking change가 플래그되었습니다. 그런데 그 변경 사항은 일주일 전에 이미 배포되었고, 아무것도 깨지지 않았습니다.
차이점(delta)은 status 필드의 enum이 ["queued","shipped","failed"]에서 ["queued","shipped"]로 줄어든 것이었습니다. differ는 전형적인 breaking change라고 말했습니다. 하지만 그 필드는 응답 스키마에 존재했습니다. 더 적은 enum 값을 반환하는 서버가 이미 세 가지를 모두 처리할 수 있는 클라이언트를 놀라게 할 수는 없습니다 — 클라이언트의 switch 문은 여전히 컴파일됩니다. 서버는 데이터가 줄어든 것이 아니라, 종류(variety)가 줄어들 것이라고 약속한 것입니다.
그때 깨달았습니다: breaking-ness에는 방향성이 있으며, 동일한 텍스트적 차이(textual delta)도 스키마가 어느 쪽을 가리키는지에 따라 의미가 바뀐다는 것을요.
- Request schema (서버가 더 엄격해짐): enum 축소, 속성 필수화,
number를integer로 좁히기 — 모두 breaking입니다. 구형 클라이언트들이 거부되는 페이로드(payload)를 보내기 시작합니다. - Response schema (서버가 적게 보장함): 필수 속성 제거, enum 확장, 타입 완화 — breaking입니다. 클라이언트들은 예상하지 못한 것들을 받게 됩니다.
반대 경우도 이전에 저를 당황하게 했습니다: 응답 enum에 값을 추가하는 것은 구형 클라이언트들이 갑자기 유효성 검사기(validators)가 거부하는 데이터를 받는 것을 의미합니다. 동일한 작업이지만, 경계 측면(boundary side)에 따라 반대되는 판결이 내려집니다.
두 번째 수정 사항은 덜 화려했습니다: 이제 diff를 수행하기 전에 스펙을 정규화(normalize)합니다 — $ref 확장, 키 정렬, 표준화(canonicalize). 이것 없이는, 속성 순서가 우연히 다르게 지정된 의미적으로 동일한 두 개의 스펙이 가짜 diff의 벽을 만들어냈을 것입니다. JSON 비교는 의미적 비교가 아닙니다.
방향 인식 버전은 이제 어떤 것이 배포되기 전에 저의 스펙 릴리스를 게이트합니다. 저는 결국 이를 OpenAPI Changelog Generator로 패키징했습니다. 이는 기본 스펙 URL과 새로운 스펙을 받아 사람이 읽기 쉬운 변경 로그와 기계가 읽을 수 있는 변경 목록을 반환합니다.
만약 단순한 속성 레벨 도구로 스펙을 비교한다면, 변경된 스키마가 경계의 어느 쪽에 위치하는지 확인해야 합니다. 이는 예상보다 더 자주 판결을 뒤집습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기