Postman 컬렉션과 OpenAPI 스펙에 대한 질문은 팀이 몇 명 이상의 엔지니어로 성장할 때마다 제기됩니다. 6개월 전에 작성한 컬렉션을 열어보면 이제 필수 필드가 3개 더 추가되었고, 매개변수 2개가 더 이상 사용되지 않으며, 서버가 실제로 반환하는 것과 더 이상 일치하지 않는 응답 형태를 가진 엔드포인트를 설명하고 있음을 발견합니다. Git의 OpenAPI 스펙은 뭔가 다르게 말합니다. Swagger UI는 또 다른 것을 말합니다. 아무도 어떤 것이 맞는지 확신하지 못합니다.
이러한 불일치는 도구의 실패가 아닙니다. 이것은 워크플로우의 실패이며, 그 차이가 중요합니다. Postman은 요청 실행, 스크립팅, 탐색적 테스트에 탁월한 도구입니다. 문제는 팀이 컬렉션을 API 계약 자체로 취급하는 경우입니다. 그 계약에서 파생된 하나의 아티팩트로 취급하지 않고 말이죠.
컬렉션이 애초에 불일치하는 이유
Postman 컬렉션은 요청 우선 아티팩트입니다. 요청을 보내고, 응답을 관찰하고, 저장합니다. 시간이 지나면서 사전 요청 스크립트, 변수 대체, 테스트 어설션, 그리고 API가 공식적으로 지정하는 것이 아니라 팀이 API에 대해 생각하는 방식을 반영하는 폴더 구조를 추가하게 됩니다.
반면에 OpenAPI 스펙은 계약 우선 아티팩트입니다. 도구가 검증하고, 모의하고, 코드를 생성할 수 있는 기계 판독 가능한 형식으로 경로, 매개변수, 스키마 및 응답 유형을 선언합니다.

두 아티팩트는 서로 다른 질문에 답합니다. 컬렉션은 “오늘 이 엔드포인트를 어떻게 호출하나요?”에 답합니다. 스펙은 “이 API는 무엇을 해야 하나요?”에 답합니다. 팀이 둘 다 독립적으로 유지 관리할 때, 필연적으로 불일치가 발생합니다. 한 개발자는 풀 리퀘스트를 병합할 때 스펙을 업데이트하고, 다른 개발자는 테스트가 깨진 것을 발견할 때 컬렉션을 업데이트합니다. 아무도 둘을 병합하지 않습니다. 몇 달 안에 동일한 API에 대한 두 개의 부분적으로만 정확한 설명을 갖게 되며, 어떤 것이 더 최신인지 알 수 있는 신뢰할 수 있는 방법이 없습니다.
이 패턴에 대한 고객의 증거는 명확합니다. 인벤티스 코리아는 정확히 이 문제를 보고했습니다: 그들의 팀은 API를 구축하고, Swagger용 OpenAPI 스펙을 생성하고, 테스트를 위해 Postman으로 컬렉션을 가져온 다음, 세 가지 표현을 동기화 상태로 유지하기 위해 지속적인 노력을 기울였습니다. 컬렉션이 전체 스키마를 반영하지 않았기 때문에 테스트에서 엣지 케이스를 놓쳤습니다. 스펙이 테스트 생성의 입력이 아니었기 때문에 문서가 불일치했습니다. 이것들은 엣지 케이스가 아닙니다. 대규모 요청 우선 워크플로우에서 예측 가능한 결과입니다.
근본 원인: Postman은 스펙 저장소로 설계되지 않았습니다
Postman 컬렉션은 자체 형식을 가지고 있습니다. Postman 컬렉션 스키마는 요청, 스크립트 및 폴더 계층을 설명하는 독점 JSON 구조입니다. 이는 OpenAPI가 아닙니다. Postman은 OpenAPI를 가져오고 내보낼 수 있지만, 양방향 변환은 손실이 발생합니다. OpenAPI-to-collection은 요청으로 표현할 수 없는 스키마 세부 정보를 삭제하고, collection-to-OpenAPI는 스펙 필드로 표현할 수 없는 스크립트와 데이터를 삭제합니다.
이것은 Postman에 대한 비판이 아닙니다. 이것은 도구가 실제로 무엇을 위한 것인지에 대한 설명입니다. Postman은 요청 중심 모델을 기반으로 구축된 협업 기능을 갖춘 요청 실행 도구입니다. 이를 정식 API 설명으로 사용하려면 형식이 지원하도록 설계되지 않은 구조를 강요해야 합니다.
단일 엔드포인트에 대한 두 가지 표현을 비교해 보세요:
| 속성 | Postman 컬렉션 | OpenAPI 스펙 |
|---|---|---|
| 요청 매개변수 | 선택적 설명과 함께 키-값 쌍으로 저장됨 | required 및 schema 필드를 사용하여 유형화되고 유효성 검사됨 |
| 응답 형태 | 저장된 예시로 캡처됨 (선택 사항) | 경로 전반에 걸쳐 $ref 재사용을 포함하는 JSON 스키마로 정의됨 |
| 오류 응답 | 요청별로 수동 추가됨 | 공유 components/schemas와 함께 responses에 열거됨 |
| 스키마 재사용 | 없음; 요청 간 복사-붙여넣기 | components/schemas에 대한 $ref는 유효성 검사기에 의해 강제됨 |
| 기계 판독 가능한 계약 | 아니요 | 예; 도구가 서버, 클라이언트, 목을 생성할 수 있습니다 |
| Git diff 친화적 | 불투명한 ID를 가진 JSON; 의미 있게 검토하기 어려움 | YAML; 의미 있는 줄 단위 diff |
| 린트 및 유효성 검사 | 네이티브 형식에서는 아님 | Spectral, Redocly CLI 및 기타 |
위 표는 불일치가 발생하는 이유를 보여줍니다: 컬렉션은 계약을 완전히 표현할 수 없으므로 계약은 다른 곳에 존재하며, 한 쪽을 편집하고 다른 쪽을 편집하지 않는 순간 둘은 동기화되지 않습니다.
Postman 팀에게 스펙 우선 방식이 실제로 의미하는 것
스펙 우선 방식은 “어떤 코드도 작성하기 전에 모든 것을 YAML로 설계하라”는 의미가 아닙니다. 컬렉션 중심 워크플로우에서 마이그레이션하는 대부분의 팀에게는 종속성을 역전시키는 것을 의미합니다. 스펙 우선 방법론은 OpenAPI 문서를 API의 권위 있는 설명으로 Git에 저장합니다. 테스트에 사용하는 컬렉션을 포함한 다른 모든 아티팩트는 그 문서에서 파생되며, 그 반대가 아닙니다.

실제 워크플로우는 다음과 같습니다:
- 스펙은 Git에 커밋되고 PR 프로세스의 일부로 검토됩니다.
- 테스트, 목 및 문서는 스펙에서 생성됩니다.
- API가 변경되면 스펙이 먼저 변경됩니다. 다운스트림 아티팩트는 자동으로 또는 도구를 통해 업데이트됩니다.
- 팀이 탐색적 테스트에 사용하는 컬렉션은 스펙에서 생성되므로 항상 현재 계약을 반영합니다.
컬렉션은 여전히 존재합니다. 스크립트, 데이터 기반 테스트 및 환경 변수도 여전히 존재합니다. 차이점은 컬렉션이 스펙의 업스트림이 아니라 다운스트림이라는 것입니다. 스펙에 새 필드가 나타나면 생성된 컬렉션에 나타납니다. 스펙에서 필드가 제거되면 생성된 요청에 더 이상 포함되지 않으므로 테스트가 실패합니다. 불일치는 6개월 후의 발견이 아니라 CI 실패가 됩니다.
스펙에서 컬렉션을 생성하는 방법
OpenAPI 스펙에서 Postman 호환 컬렉션을 파생하는 방법은 여러 가지가 있습니다. 다음은 Redocly CLI와 함께 작동하는 한 가지 방법입니다:
# Install Redocly CLI
npm install -g @redocly/cli
# Validate the spec first
redocly lint openapi/petstore.yaml
# Bundle the spec (resolve $ref chains)
redocly bundle openapi/petstore.yaml -o dist/petstore-bundled.yaml
# Convert to Postman collection v2.1 using the openapi-to-postmanv2 library
npm install -g openapi-to-postmanv2
openapi2postmanv2 \
--spec dist/petstore-bundled.yaml \
--output dist/petstore-collection.json \
--prettyPrint
출력은 표준 Postman 컬렉션 JSON입니다. 이를 Postman으로 가져오거나 Newman 또는 Postman CLI에서 기본 컬렉션으로 사용할 수 있습니다. 사전 요청 스크립트와 환경 변수는 독립적으로 유지 관리하는 별도의 파일로 남아 있습니다. 업데이트된 스펙에서 컬렉션을 재생성할 때 덮어쓰여지지 않습니다.
이를 CI에 연결하여 테스트 실행 전에 컬렉션이 항상 스펙에서 재생성되도록 할 수 있습니다:
# .github/workflows/api-tests.yml
name: API contract tests
on:
push:
paths:
- "openapi/**"
- "src/**"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
npm install -g @redocly/cli openapi-to-postmanv2 newman
- name: Validate OpenAPI spec
run: redocly lint openapi/petstore.yaml
- name: Generate collection from spec
run: |
redocly bundle openapi/petstore.yaml -o dist/petstore-bundled.yaml
openapi2postmanv2 \
--spec dist/petstore-bundled.yaml \
--output dist/petstore-collection.json
- name: Run tests against generated collection
run: |
newman run dist/petstore-collection.json \
--environment config/env-staging.json \
--reporters cli,junit \
--reporter-junit-export results/test-results.xml
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results
path: results/
이 패턴을 사용하면 스펙이 모든 테스트 실행의 입력이 됩니다. 테스트를 깨뜨리는 스펙 변경은 스펙을 변경한 동일한 PR에서 감지됩니다.
이 워크플로우에서 Apidog의 역할
Apidog의 가치는 Postman을 요청 실행 도구로서 대체하는 데 있는 것이 아닙니다. 수동 변환 단계 없이 OpenAPI 스펙을 팀이 작업하는 모든 다른 아티팩트와 연결한다는 점입니다. Git의 스펙은 진실의 원천으로 유지되며, Apidog는 그 위에 협업 및 실행 계층입니다.
Apidog의 스펙 우선 모드 (현재 베타 중)는 Git 리포지토리에서 OpenAPI 스펙을 Apidog 워크스페이스로 직접 동기화할 수 있게 합니다. 동기화된 스펙에서 자동 생성된 목, 대화형 문서, 테스트 시나리오를 얻을 수 있으며, Git에서 스펙이 변경될 때마다 모든 것이 자동으로 업데이트됩니다. 스펙과 함께 별도의 컬렉션을 유지 관리할 필요가 없습니다. 스펙이 Apidog가 표시하고 실행하는 모든 것을 주도합니다.
이는 STC 그룹과 세계 경제 포럼이 설명한 것을 경험하는 팀에게 중요합니다. 즉, 테스트용 Postman, 스펙 렌더링용 별도 문서 도구, 프론트엔드 개발용 목 서버 등 모두 동일한 API 계약을 반영해야 하는 세 가지 시스템을 유지 관리하는 것입니다. 스펙이 변경되면 한 곳에서 업데이트하고 세 가지 표면이 모두 업데이트됩니다. Apidog의 워크스페이스 권한 및 SSO 세분성이 특정 접근 제어 요구 사항을 충족하는지 여부를 시험판에서 확인하는 것이 좋습니다. 특히 DHL 배포(100명 이상 사용자)와 같은 대규모 팀의 경우 더욱 그렇습니다. 이러한 질문은 개념 증명에 대한 의미 있는 평가 질문입니다.
마이그레이션 경로의 경우, 기존 Postman 컬렉션을 Apidog로 변환하여 시작점으로 삼은 다음, 스펙을 앞으로의 정식 문서로 만들 수 있습니다. 기계적인 가져오기 단계는 해당 링크된 가이드에서 자세히 다룹니다.
Git 워크플로우에서 스펙을 코드로 취급하기
API 스펙을 코드로 취급하는 접근 방식은 OpenAPI 문서가 애플리케이션 코드와 동일한 대우를 받는다는 것을 의미합니다. 즉, 풀 리퀘스트, 코드 리뷰, CI에서의 린팅, 릴리스 경계에서의 버전 태그 등이 해당됩니다. 대부분의 팀은 이미 이를 위한 인프라를 가지고 있음을 발견합니다. 누락된 단계는 이를 스펙 파일에 적용하는 것입니다.
도움이 되는 몇 가지 방법:
- 스펙을 별도의 "docs" 리포지토리가 아닌, 스펙이 설명하는 서비스와 동일한 리포지토리에 저장하십시오. 이렇게 하면 스펙 변경이 코드 변경과 동일한 PR에서 발생하도록 보장됩니다.
- CI 파이프라인에 Spectral 린트 단계를 추가하십시오. Spectral은 OpenAPI 스펙과 팀이 정의한 모든 사용자 지정 규칙에 대해 스펙의 유효성을 검사합니다. 손상된 스키마 참조, 누락된 설명, 일관성 없는 이름 지정은 검토 코멘트가 아니라 CI 실패가 됩니다.
- 애플리케이션 코드를 분기하는 방식과 동일하게 브레이킹 변경을 위해 브랜치 기반 스펙 개발을 사용하십시오. Apidog 워크스페이스는 스펙에 대한 브랜칭을 지원하므로, 브레이킹 변경이 검토 중인 동안 다른 팀이 안정적인 브랜치를 기반으로 작업할 수 있습니다.
- 다운스트림 소비자 리포지토리에서 스펙 버전을 고정하십시오. 서비스 B가 계약 테스트를 위해 서비스 A의 스펙에 의존하는 경우, main의 HEAD가 아닌 특정 버전 태그를 참조해야 합니다.
새 프로젝트에 대한 단계별 설정이 필요하다면 Git 기반 API 워크플로우 가이드에서 이 접근 방식을 심층적으로 다루고 있습니다.
FAQ
Postman을 완전히 사용 중단해야 하나요?
아니요. 방법론 변경은 도구 교체가 아닌 종속성 방향에 관한 것입니다. 탐색적 테스트 및 스크립팅을 위해 Postman을 계속 사용할 수 있습니다. 차이점은 컬렉션이 별도의 아티팩트로 유지 관리되는 것이 아니라 각 테스트 실행 전에 스펙에서 생성된다는 것입니다. 팀이 탐색적 작업을 위해 Postman의 UI를 선호한다면, 그 선호도는 스펙 우선 워크플로우와 호환됩니다.
기존 Postman 스크립트와 환경 변수는 어떻게 되나요?
사전 요청 스크립트, 테스트 스크립트 및 환경 변수 정의는 생성된 컬렉션의 일부가 아닙니다. 이들은 독립적으로 유지 관리하는 별도의 파일입니다. 업데이트된 스펙에서 컬렉션을 재생성할 때 스크립트는 덮어쓰여지지 않습니다. 구조적 계층(요청 정의)이 항상 스펙에서 파생되는 동안 동작 계층(스크립트)을 유지합니다.
스펙에 아직 없는 엔드포인트는 어떻게 처리하나요?
스펙 우선 워크플로우에서 스펙에 없는 엔드포인트는 테스트 준비가 되지 않은 것입니다. 이는 엄격하게 들리지만 핵심은 이겁니다: 스펙 게이트는 새로운 엔드포인트에 대한 테스트가 작성되기 전에 공식적으로 설명되도록 보장합니다. 탐색적 개발의 경우, 로컬 스텁을 기반으로 작업하고 엔드포인트를 도입하는 PR의 일부로 스펙 항목을 추가할 수 있습니다. 스펙 우선 편집 단계를 더 빠르게 만드는 도구에 대해서는 최고의 OpenAPI 유효성 검사 도구 가이드를 참조하십시오.
Apidog 스펙 우선 모드를 지금 사용할 수 있나요?
Apidog 스펙 우선 모드는 현재 베타 중입니다. Apidog를 통해 접근하여 Git 동기화 워크플로우, 브랜치 지원 및 자동 생성된 목이 팀의 요구 사항을 충족하는지 평가할 수 있습니다. 다른 모든 베타 기능과 마찬가지로, 프로덕션 워크플로우로 사용하기 전에 특정 스펙 구조에 대해 테스트해 볼 가치가 있습니다.
이것과 내 스펙을 Postman으로 가져오는 것의 차이점은 무엇인가요?
Postman은 OpenAPI 스펙을 가져와 컬렉션을 생성할 수 있습니다. 이는 일회성 변환입니다. 컬렉션은 스펙과 독립적으로 유지 관리되므로 불일치가 즉시 다시 발생합니다. 스펙 우선 워크플로우는 모든 CI 실행(또는 동기화) 시 스펙에서 컬렉션을 재생성하므로, 컬렉션이 스펙과 한 빌드 이상 차이 나는 일이 없습니다.
결론
팀이 겪고 있는 불일치 문제는 Postman의 버그가 아닙니다. 이는 두 개의 부분적으로 겹치는 API 설명을 명확한 종속성 없이 유지 관리할 때 발생하는 예측 가능한 결과입니다. 해결책은 Git의 OpenAPI 스펙을 권위 있는 소스로 설정하고, Postman 컬렉션을 해당 스펙의 다운스트림에서 생성된 아티팩트로 취급하는 것입니다.
이러한 역전은 무엇이 언제 깨지는지를 바꿉니다. 테스트를 깨뜨리는 스펙 변경은 변경을 일으킨 PR에서 감지됩니다. 문서, 목, 테스트 시나리오는 모두 동일한 소스에서 읽기 때문에 일관성을 유지합니다. 두 시스템을 동기화 상태로 유지하는 유지 관리 부담은 시스템이 하나뿐이기 때문에 사라집니다.
Apidog를 다운로드하여 기존 OpenAPI 스펙으로 스펙 우선 모드 워크스페이스를 여십시오. 스펙이 아닌 컬렉션에서 시작하는 경우, 컬렉션을 OpenAPI 시작점으로 가져온 다음 거기서부터 스펙 우선 방식으로 작업할 수 있습니다. 꾸며낸 예시가 아니라 자신의 API에 대해 실행되는 것을 보면 Git 동기화 워크플로우가 구체화될 것입니다.
