대부분의 API 팀은 계약을 나중에 고려합니다. 코드를 먼저 작성하고 사양을 생성한 다음, 둘이 서로 멀어지는 것을 지켜봅니다. Git-네이티브 API 디자인은 이 순서를 뒤집습니다. API 계약을 소스 코드처럼 취급하고, Git에서 버전을 관리하며, 애플리케이션 로직을 검토하는 것과 동일한 방식으로 모든 변경 사항을 검토합니다.
이 가이드는 단일 도구가 아닌 규율에 관한 것입니다. 브랜치에서 계약을 설계하고, 풀 리퀘스트에서 검토하며, 커밋된 사양을 모의(mock), 테스트 및 문서로 전환하는 방법을 배우게 될 것입니다. 목표는 Git 기록이 곧 API 기록이 되는 워크플로를 만드는 것입니다.
Spec-First 툴링이 무엇인지 이미 알고 제품 사용 방법을 원한다면, Git-네이티브 API 워크플로에 대한 관련 글을 읽어보세요. 이 글은 실천에 중점을 둡니다.
API 작업에서 "Git-네이티브"의 의미
Git-네이티브는 API 정의가 독점 클라우드 데이터베이스나 공급업체 로그인 뒤가 아니라, 팀이 이미 사용하는 동일한 버전 관리 시스템으로 추적되는 일반 텍스트 파일로 코드 옆 저장소에 존재한다는 것을 의미합니다. .yaml 또는 .json 파일 형식으로 말이죠.
이를 클라우드 종속 도구와 비교해보세요. 많은 API 디자인 플랫폼은 자체 백엔드에 계약을 저장합니다. 웹 UI를 통해 편집하며, 정식 버전은 해당 서버에 존재합니다. 여러분의 저장소는 기껏해야 오래된 내보내기 파일을 가지고 있을 뿐입니다. 공급업체의 데이터베이스가 진실의 원천이라면, Git 기록은 API가 어떻게 진화했는지에 대해 아무것도 알려주지 않습니다.

Git-네이티브 모델은 그러한 관계를 뒤집습니다. main 브랜치의 파일이 계약입니다. 모든 다른 것들, GUI를 포함하여, 그 파일에 대한 뷰일 뿐입니다. 이 한 번의 변화로 API 표면에 대한 기록, 책임 추적, 롤백, 검토 기능이 해제됩니다.
Git-네이티브 설정은 세 가지 속성을 가집니다. 사양은 저장소 내의 텍스트 파일입니다. 변경 사항은 브랜치, 커밋, 병합과 같은 일반적인 Git 작업을 통해 이루어집니다. 그리고 모의(mock)부터 문서까지 모든 다운스트림 아티팩트는 별도의 데이터베이스가 아닌 커밋된 파일에서 파생됩니다.
Git에서 API를 설계하고 개발해야 하는 이유
여러분은 이미 가장 소중한 자산인 코드에 Git을 신뢰하고 있습니다. API 계약도 동일한 대우를 받을 자격이 있습니다.
기록이 첫 번째 이유입니다. 누군가 "cursor 페이지네이션 파라미터는 언제 추가되었나요?"라고 물으면, git log가 몇 초 만에 답합니다. 이를 도입한 커밋에는 메시지, 작성자, 날짜가 있습니다. 스크린샷도, 변경 로그 발굴도 필요 없습니다.
책임 추적은 두 번째입니다. 사양 파일에 git blame을 실행하면 각 줄을 누가 왜 변경했는지 정확히 알 수 있습니다. 혼란스러운 필드 이름은 이를 추가한 PR과 연결된 논의까지 거슬러 올라갑니다. 책임은 자동으로 명확해집니다.
롤백은 세 번째입니다. 나쁜 디자인이 배포되었습니다. Git을 사용하면 병합을 git revert하여 계약을 이전 상태로 되돌릴 수 있습니다. 다운스트림 코드 생성기, 모의(mock), 문서는 되돌려진 파일에서 다시 생성됩니다. 별도의 시스템에서 수동으로 정리할 필요가 없습니다.
검토는 네 번째이며, 팀이 충분히 활용하지 못하는 부분입니다. 풀 리퀘스트는 API 디자인이 실제 구현되기 *전에* 논의하기에 자연스러운 장소입니다. 검토자는 필수 필드를 추가하는 + 줄에 댓글을 달 수 있습니다. 대화는 변경 사항 옆에 영원히 남아있습니다.
단일 진실 원천이 모든 것을 연결합니다. 계약이 main 브랜치의 단일 파일일 때, 어떤 버전이 실제인지에 대한 모호함이 없습니다. 프론트엔드, 백엔드, QA, 문서 모두 동일한 YAML 줄을 읽습니다. 이것이 Git 기반 API 사양 워크플로의 핵심 약속입니다.
Git-네이티브 API 설계 루프
루프는 다섯 단계로 구성됩니다: 계약 설계, 커밋, PR 열기, 검토, 병합. 구현은 병합 후에 이루어지며, 그 반대가 아닙니다.
계약 작성을 시작하세요. 사용자 송장(invoice)을 가져오는 엔드포인트를 추가한다고 가정해 봅시다. 브랜치를 생성하고 OpenAPI 파일을 편집합니다.
# openapi.yaml (feat/invoices-list 브랜치에 추가된 발췌 부분)
paths:
/users/{userId}/invoices:
get:
operationId: listUserInvoices
summary: List invoices for a user
parameters:
- name: userId
in: path
required: true
schema: { type: string, format: uuid }
- name: status
in: query
required: false
schema:
type: string
enum: [draft, open, paid, void]
responses:
"200":
description: A page of invoices
content:
application/json:
schema:
$ref: "#/components/schemas/InvoiceList"
"404":
description: User not found
명확한 메시지로 변경 사항을 커밋합니다: git commit -m "Add GET /users/{userId}/invoices contract". 커밋은 작고 집중적입니다. 하나의 설계 결정을 설명합니다.
이제 풀 리퀘스트를 엽니다. diff는 검토자에게 무엇이 새로운지 정확히 보여줍니다: 하나의 경로, 하나의 작업, 두 개의 파라미터, 두 개의 응답. 팀원들은 명명 규칙, enum 값, 그리고 404가 존재하지 않는 사용자에 대한 올바른 코드인지 논의합니다. 핸들러 코드 한 줄도 작성되기 전에 커서 페이지네이션을 추진할 수도 있습니다.
PR이 승인되면 병합합니다. main 브랜치의 계약은 이제 송장(invoice) 엔드포인트를 포함합니다. 구현은 그 다음에 오며, 여러분 모두가 동의한 사양에 의해 제약됩니다. 이 순서가 바로 사람들이 사양 우선 API 개발이라고 부르는 것입니다: 합의가 코드보다 우선합니다.
그 결과는 설계 논의가 저렴하게 이루어진다는 것입니다. 검토 중 YAML 필드를 변경하는 데는 몇 분이 걸리지만, 이미 배포되고 구현되었으며 문서화된 엔드포인트를 변경하는 데는 며칠이 걸립니다.
API 계약을 위한 브랜칭 전략
계약 변경 사항을 다른 변경 사항과 동일하게 취급하세요: 작업의 논리적 단위당 하나의 브랜치. 엔드포인트 또는 수정 사항당 하나의 브랜치는 PR을 작게 유지하고 diff를 읽기 쉽게 만듭니다.
의도를 명확하게 드러내도록 브랜치 이름을 지정하세요. 변경 클래스를 나타내는 접두사를 사용하세요. 이는 검토자와 CI가 작업을 라우팅하는 데 도움이 됩니다.
| 변경 유형 | 브랜치 접두사 | 예시 | 검토 중요도 |
|---|---|---|---|
| 새 엔드포인트 | feat/api- |
feat/api-invoices-list |
표준 |
| 추가 필드 | feat/api- |
feat/api-invoice-currency |
낮음 |
| 호환성 파괴 변경 | break/api- |
break/api-remove-legacy-id |
높음, 승인 필요 |
| 사양 버그 수정 | fix/api- |
fix/api-status-enum-typo |
낮음 |
| 리팩토링만 해당 | chore/api- |
chore/api-reorder-schemas |
낮음 |
접두사는 의미를 전달합니다. break/api- 브랜치는 검토자에게 속도를 늦추고 모든 소비자(consumer)를 확인하라고 알려줍니다. chore/api- 브랜치는 의미론적 변경이 없음을 알리므로 검토가 빠르게 진행될 수 있습니다.
브랜칭 모델도 선택합니다. 트렁크 기반 개발은 대부분의 API 팀에 적합합니다. 짧게 유지되는 브랜치는 매일 main으로 병합되며, 사양은 단일 진실 라인에 가깝게 유지됩니다. 장기 실행 develop 및 release 브랜치를 사용하는 Gitflow는 API 변경 사항을 예정된 릴리스로 일괄 처리하는 팀에 적합합니다.
| 모델 | 최적의 용도 | API 트레이드오프 |
|---|---|---|
| 트렁크 기반 | 지속적 배포, 소규모 팀 | 계약이 작은 단계로 진화; 병합 고통 감소 |
| Gitflow | 예정된 릴리스, 규제된 배포 | develop에서 사양 분기; 더 크고 위험한 병합 |
대부분의 API 작업에는 트렁크 기반을 선호하세요. 작고 빈번한 계약 변경은 작고 빈번한 diff를 생성합니다. 장기 실행 브랜치는 사양을 표류하게 만들고, 두 브랜치가 동일한 파일을 재구성할 때 YAML 병합 충돌은 빠르게 복잡해집니다.
풀 리퀘스트에서 API 디자인 검토하기
사양 PR은 구문 검사가 아니라 디자인 검토입니다. 검토자는 의미론을 살펴보고, 몇 가지 질문으로 대부분의 위험을 다룰 수 있습니다.
이것이 기존 소비자(consumer)에게 호환성 파괴를 일으키는가? 필드 제거, 경로 이름 변경, 타입 강화는 모두 호환성 파괴 변경입니다. 검토자는 변경 사항이 추가적인지 또는 호환성 파괴적인지 확인하며, 호환성 파괴 변경은 버전 업그레이드 또는 폐기 경로를 요구합니다.
명명 규칙이 일관적인가? 모든 컬렉션 엔드포인트가 복수 명사를 사용한다면, 새로운 단수 경로는 눈에 뜁니다. 다른 곳에서 오류가 code 필드를 반환한다면, 새 엔드포인트도 그래야 합니다. 검토자는 API가 이미 설정한 패턴을 강제합니다.
diff에 친화적인가? YAML을 안정적으로 유지하여 diff가 작게 유지되도록 하세요. 키 순서를 일관되게 유지하세요. 새로운 경로는 예측 가능한 위치에 추가하세요. 검토자는 5줄짜리 diff를 몇 초 만에 읽을 수 있지만, 재정렬된 파일은 실제 변경 사항을 숨기는 100줄짜리 diff를 생성합니다.
검토자 친화적인 호환성 파괴 변경. - 줄은 정확히 무엇이 사라지는지 나타냅니다.
# PR에서 검토자가 보는 Diff
parameters:
- name: status
in: query
schema:
type: string
- enum: [draft, open, paid, void]
+ enum: [draft, open, paid, void, uncollectible]
해당 diff는 enum에 추가되는 것이므로 안전합니다. 이를 void를 완전히 제거하는 - 줄과 비교해보세요. 이는 해당 값을 보내는 모든 클라이언트를 손상시킬 것입니다. diff는 차이점을 한눈에 보이게 합니다.
검토자가 코드에 댓글을 다는 것과 동일한 방식으로 사양에 인라인으로 댓글을 달도록 권장하세요. 토론은 해당 줄에 연결되어 병합된 기록에 계속 남아있습니다.
설계에서 개발로
계약이 main 브랜치에 있으면, 모든 다운스트림의 원천이 됩니다. 수동으로 작성하는 것이 아니라 생성하는 것입니다.

코드 생성이 먼저 이루어집니다. openapi-generator와 같은 도구는 커밋된 파일에서 서버 스텁과 타입이 지정된 클라이언트를 생성합니다. 핸들러는 비즈니스 로직을 채우지만, 요청 및 응답 형태는 구조적으로 계약과 일치합니다. 사양과 코드는 와이어 형식에 대해 불일치할 수 없습니다.
다음은 모의(mock)입니다. 모의 서버는 사양을 읽고 모든 엔드포인트에 대한 예시 응답을 반환합니다. 프론트엔드 개발자는 백엔드가 존재하기 전에 모의를 기반으로 개발합니다. 그들은 계약이 병합되는 순간부터 시작하며, 몇 주 후가 아닙니다.
테스트가 뒤따릅니다. 계약 테스트는 실행 중인 서버가 사양과 일치하는지 확인합니다. 요청을 보내고, 스키마에 대해 응답을 검증하며, 불일치할 경우 빌드를 실패시킵니다. 이것이 사양/코드 불일치를 방지하는 안전장치입니다.
문서도 생성됩니다. 참조 문서는 OpenAPI 파일에서 직접 렌더링됩니다. 계약이 변경되면 동일한 커밋에서 문서도 변경됩니다. 잊어버릴 수 있는 별도의 문서 업데이트가 없습니다.
원칙은 일관됩니다. 모든 아티팩트는 하나의 커밋된 파일에서 파생됩니다. 각 병합 시 다시 생성하면, 모의(mock), 클라이언트, 테스트 및 문서가 계약과 완벽하게 일치하게 됩니다.
확장 가능한 팀 컨벤션
컨벤션은 팀이 성장함에 따라 Git-네이티브 워크플로가 무너지지 않도록 유지하는 요소입니다. 초기에 결정하고 문서화하세요.
첫째, 하나의 사양 파일과 여러 사양 파일 중 선택합니다. 단일 openapi.yaml은 간단하지만 수십 개의 엔드포인트를 넘어가면 다루기 힘들어집니다. $ref 참조를 사용하여 여러 파일로 분할하면 번들링 단계라는 비용을 감수하고 각 파일을 읽기 쉽게 유지할 수 있습니다. 일반적인 패턴은 리소스당 하나의 파일이며, 빌드 시점에 단일 사양으로 묶이는 것입니다.
둘째, 의도적으로 버전을 관리합니다. 의미 있는 변경이 있을 때마다 OpenAPI info.version을 올리고, 의미론적 버저닝을 따릅니다. 추가적인 변경은 마이너 버전을 올립니다. 호환성 파괴 변경은 메이저 버전을 올리며, 일반적으로 /v2/와 같은 새로운 경로 접두사를 의미합니다.
셋째, 변경 로그를 유지합니다. 사양 옆의 CHANGELOG.md는 무엇이 변경되었고 왜 변경되었는지 인간적인 용어로 기록합니다. Git 기록은 정확하지만 장황합니다. 변경 로그는 소비자가 실제로 훑어보는 읽기 쉬운 요약입니다.
넷째, CODEOWNERS로 사양을 보호합니다. API 담당자가 계약 파일에 대한 모든 변경을 승인하도록 요구합니다. 이는 선의의 기여자들이 일관성 없는 디자인을 배포하는 것을 막습니다.
# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
다섯째, CI에서 린트(lint)를 실행합니다. 린터는 검토 전에 스타일 및 일관성 문제를 잡아냅니다. 모든 PR에서 린터를 실행하여 사람이 포맷팅이 아닌 디자인을 검토하도록 합니다.
# .github/workflows/api-lint.yml
name: API 린트
on:
pull_request:
paths: ["api/"]
jobs:
spectral:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Spectral 실행
run: npx @stoplight/spectral-cli lint api/openapi.yaml --fail-severity warn
CI 린팅과 CODEOWNERS를 함께 사용하면 모든 계약 변경 사항에 대해 자동화된 검사와 담당자(steward)의 확인을 받게 됩니다. 이러한 조합은 3명의 엔지니어에서 300명으로 확장될 수 있습니다.
일반적인 함정 및 피하는 방법
Git-네이티브 API 디자인에는 예측 가능한 실패 모드가 있습니다. 이를 아는 것은 우회 설계를 하는 데 도움이 됩니다.
사양/코드 불일치가 최악입니다. 계약은 한 가지를 말하지만, 실행 중인 서버는 다른 것을 합니다. 커밋된 사양에 대해 실시간 응답을 검증하는 CI의 계약 테스트로 이를 방지하세요. 불일치하면 빌드가 실패합니다. 불일치는 프로덕션의 놀라움이 아니라 깨진 파이프라인이 됩니다.
거대한 PR은 다음 함정입니다. 20개의 엔드포인트를 추가하는 단일 브랜치는 검토 불가능한 diff를 생성합니다. 검토자는 대충 훑어보고 승인하며 문제를 놓칩니다. 작업을 PR당 하나의 엔드포인트 또는 하나의 변경으로 분할하세요. 작은 diff는 실제 검토를 받습니다.
수동으로 작성된 아티팩트는 조용한 불일치를 유발합니다. 누군가 클라이언트를 생성하는 대신 수동으로 작성하면, 클라이언트는 사양에서 벗어납니다. 매번 커밋된 파일에서 클라이언트, 스텁 및 문서를 생성하세요. 수동으로 작성된 API 아티팩트는 좋지 않은 징후로 간주하세요.
YAML 병합 충돌은 장기 실행 브랜치를 사용하는 팀을 좌절시킵니다. 두 브랜치가 동일한 파일을 재구성하고 Git은 이를 조정할 수 없습니다. 짧게 유지되는 브랜치, 안정적인 키 순서, 그리고 변경 사항이 다른 파일을 건드리도록 분할된 파일 레이아웃으로 이를 피하세요. 트렁크 기반 개발과 작은 PR은 대부분의 충돌을 시작 전에 제거합니다.
네 가지 모두에서 패턴은 동일합니다. 변경 사항을 작게 유지하고, 사양에서 아티팩트를 파생시키며, CI가 계약을 강제하도록 합니다. 규율이 영웅적인 행동보다 낫습니다.
Apidog의 역할
텍스트 편집기와 CLI로 Git-네이티브 워크플로를 실행할 수 있습니다. 많은 팀이 Git을 진실의 원천으로 포기하지 않으면서 디자인을 위한 GUI를 원합니다. 그것이 Apidog의 Spec-First 모드가 채우는 간극입니다.
Spec-First 모드는 OpenAPI 파일을 Git 저장소에 유지하며 양방향 동기화를 제공합니다. Apidog의 비주얼 디자이너나 에디터에서 계약을 편집할 수 있으며, 둘 모두 저장소의 파일과 일관성을 유지합니다. Git의 파일은 정식 버전으로 남아 있으므로, 브랜치, PR 및 기록이 여기 설명된 대로 정확히 작동합니다. 클라우드 종속 없이 GUI를 얻을 수 있습니다. 설정 세부 정보는 Spec-First 모드 문서를 참조하세요.
중요한 것은 도구가 아닙니다. 시각적 디자인 표면과 Git-네이티브 규율을 동시에 가질 수 있다는 것입니다. 저장소는 단일 진실 원천으로 유지되며, Apidog는 그 위에 하나의 뷰가 됩니다.
자주 묻는 질문
Git-네이티브 API 디자인은 OpenAPI에만 적용되나요?
아니요. 이 규율은 모든 텍스트 기반 계약 형식에 적용됩니다. OpenAPI가 가장 일반적이지만, AsyncAPI, gRPC .proto 파일 또는 GraphQL SDL에도 동일한 워크플로가 작동합니다. 계약이 diff, 브랜치, 검토가 가능한 텍스트 파일인 한 Git-네이티브입니다.
Git-네이티브 워크플로에서 호환성 파괴 변경은 어떻게 처리하나요?
호환성 파괴 변경을 가시적이고 의도적으로 만드세요. break/api- 브랜치 접두사를 사용하고, 메이저 버전을 올리며, CODEOWNERS를 통해 담당자의 승인을 요구하세요. 가능하다면, 새 형태를 이전 형태와 함께 추가하고, 이전 경로는 일정에 따라 폐기하세요. PR diff와 버전 업그레이드는 함께 모든 소비자에게 호환성 파괴를 알립니다.
API 사양은 코드와 같은 저장소에 있어야 하나요?
일반적으로 한 팀이 둘 다 소유하는 경우 그렇습니다. 사양과 구현을 함께 두는 것은 단일 PR이 계약과 핸들러를 동시에 변경할 수 있고, 계약 테스트가 하나의 파이프라인에서 실행됨을 의미합니다. 여러 팀이 하나의 공유 API를 사용하고 독립적인 버저닝이 필요할 때만 사양을 별도의 저장소에 두세요.
사양과 코드가 서로 멀어지는 것을 어떻게 방지하나요?
CI에 계약 테스트를 추가하세요. 이들은 실행 중인 서버에 실제 요청을 보내고, 커밋된 사양에 대해 모든 응답을 검증합니다. 불일치는 빌드를 실패시킵니다. 사양에서 스텁과 클라이언트를 생성하는 것과 결합하여, 계약 테스트는 불일치를 프로덕션 버그가 아닌 파이프라인 실패로 만듭니다.
결론
Git-네이티브 API 디자인은 제품이 아닌 규율입니다. 계약을 소스 코드처럼 취급하고, 브랜치에서 발전시키며, 풀 리퀘스트에서 검토하고, 커밋된 파일에서 모든 다운스트림 아티팩트를 생성합니다. Git이 이미 제공하기 때문에 기록, 책임 추적, 롤백 및 검토가 무료로 제공됩니다.
작게 시작하세요. 사양을 저장소로 옮기고, 린트 단계를 추가하며, 계약 변경 사항에 대한 검토를 의무화하세요. 거기서부터 코드 생성, 모의(mock), 계약 테스트로 발전시키세요. 워크플로는 복합적으로 작용합니다: 각 컨벤션은 다음 컨벤션을 더 쉽게 만들고, Git 기록은 API가 어떻게 성장했는지에 대한 완전한 기록이 됩니다.
사양을 Git에 유지하는 시각적 디자인 표면을 원한다면, Apidog의 Spec-First 모드를 사용해보고 양방향 동기화가 위 워크플로에 어떻게 적합한지 확인하세요.
