대부분의 API 버그는 코딩 실수가 아닙니다. 그것들은 합의 오류입니다. 프론트엔드가 userId를 예상했지만, 백엔드는 user_id를 보냈고, QA에서 발견할 때까지 아무도 알아채지 못했습니다. 스펙 우선(Spec-first) API 개발은 문서를 마지막에 작성하는 것이 아니라 계약을 가장 먼저 작성함으로써 이러한 문제를 해결합니다.
이 가이드에서는 작은 OpenAPI 스펙을 수동으로 작성한 다음, 이 단일 파일을 사용하여 서버 코드가 존재하기 전에 목(mock), 테스트 및 문서를 생성하는 방법을 알아볼 것입니다. 동일한 접근 방식은 몇 가지 이름으로 불립니다: 스펙 주도 개발(spec-driven development), 디자인 우선(design-first), 또는 계약 우선(contract-first). 이 모든 용어는 동일한 아이디어를 가리킵니다. 인터페이스에 먼저 합의한 다음, 그것에 맞춰 구축하는 것입니다.
스펙 우선 API 개발이란 무엇인가요?
스펙 우선 API 개발이란 엔드포인트를 구현하기 전에 기계가 읽을 수 있는 계약, 일반적으로 OpenAPI 문서를 작성하는 것을 의미합니다. 이 계약은 모든 경로, 매개변수, 요청 본문, 응답 형태 및 상태 코드를 설명합니다. 일단 존재하면, API를 다루는 모든 사람에게 진실의 원천이 됩니다.
스펙은 코드 뒤에 따라오는 문서가 아닙니다. 그것이 주도합니다. 프론트엔드 팀은 스펙으로부터 생성된 목(mock)을 기반으로 구축합니다. QA는 스펙을 기반으로 테스트를 작성합니다. 백엔드는 스펙을 만족시키기 위해 구현합니다. 이 세 가지 팀 모두가 동일한 파일에 동의하면, 통합은 더 이상 추측 게임이 아니게 됩니다.
이것은 일반적인 순서를 뒤바꿉니다. 코드 우선 개발에서는 핸들러를 작성한 다음 나중에, 종종 수동으로, 종종 스프린트 내에서 오래된 상태로 설명합니다. 디자인 우선 워크플로에서는 설명이 먼저 오고 코드가 그것에 응답합니다. 이 단일 변경으로 대부분의 통합 문제가 프로젝트 시작 시점으로 이동하며, 이 시점에서는 수정 비용이 저렴합니다.
스펙 우선 vs 코드 우선 라이프사이클
두 접근 방식 모두 동일한 엔드포인트를 생성합니다. 문제는 언제 드러나는지, 그리고 누가 병렬로 작업을 시작할 수 있는지에 차이가 있습니다.

오른쪽 열은 그 이점입니다. 계약이 먼저 존재하면, 세 팀이 서로를 방해하지 않고 하나의 공유된 정의에 따라 구축을 시작할 수 있습니다.
작업된 OpenAPI 예시
작은 /users 엔드포인트를 단계별로 설계해 봅시다. 각 부분이 명확하도록 조각별로 만들고, 나중에 전체 파일을 조립할 것입니다.
문서 헤더부터 시작합니다. 이는 OpenAPI 버전과 기본 메타데이터를 선언합니다.
openapi: 3.0.3
info:
title: Users API
version: 1.0.0
servers:
- url: https://api.example.com/v1
다음으로, components 아래에 User 스키마를 정의합니다. 한 번 정의하면 모든 곳에서 참조할 수 있으므로, 요청 및 응답 전반에 걸쳐 형태가 일관되게 유지됩니다.
components:
schemas:
User:
type: object
required: [id, email, createdAt]
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
createdAt:
type: string
format: date-time
이제 GET /users 경로를 추가합니다. 이는 사용자를 나열하고 limit 쿼리 매개변수를 지원합니다. 응답이 User 스키마를 재정의하는 대신 $ref를 사용하여 재사용하는 방식에 주목하세요.
paths:
/users:
get:
summary: List users
operationId: listUsers
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: A list of users
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
사용자를 생성하는 POST /users 작업을 추가합니다. 요청 본문은 클라이언트가 보내야 할 것을 정의하고, 201 응답은 생성된 레코드를 반환합니다.
post:
summary: Create a user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email]
properties:
email:
type: string
format: email
name:
type: string
responses:
"201":
description: User created
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: Invalid request body
이것은 완전하고 유효한 계약입니다. 모든 필드의 이름을 지정하고, email을 필수로 표시하며, limit을 100으로 제한하고, 성공 및 오류 응답을 모두 선언합니다. 아직 서버 코드를 한 줄도 작성하지 않았지만, 합의는 확정되었습니다.
스펙으로부터 목(mock), 테스트, 문서를 생성
스펙을 먼저 작성하는 이유는 레버리지 때문입니다. 하나의 파일이 팀들이 일반적으로 개별적으로 구축하는 세 가지 산출물을 구동합니다.
목(Mocks). 목 서버는 스펙을 읽고 모든 스키마와 일치하는 예시 응답을 반환합니다. format: uuid 및 format: email 힌트는 도구가 현실적인 샘플 데이터를 생성하도록 합니다. 프론트엔드는 GET /users를 호출하고 실제 핸들러가 존재하기 훨씬 전인 첫날부터 잘 구성된 사용자 배열을 얻습니다. 스펙이 변경되면, 목(mock)도 함께 변경됩니다.
테스트. 스펙은 필수 필드, 유형 및 상태 코드를 선언하므로, 테스트 오라클 역할도 합니다. 계약 테스트는 POST /users에 대한 실제 응답이 User 스키마와 일치하는 본문과 함께 201을 반환하고, email이 누락되었을 때는 400을 반환하는지 확인합니다. 여러분은 어설션(assertion)을 새로 만드는 것이 아니라, 구현이 이미 합의한 내용과 일치하는지 확인하는 것입니다.
문서(Docs). API 참조 문서는 스펙에서 직접 렌더링됩니다. 문서에서 볼 수 있는 모든 엔드포인트, 매개변수 및 예시는 동일한 YAML에서 나옵니다. 동기화해야 할 두 번째 사본이 없으므로, 문서는 계약에서 벗어날 수 없습니다.
이것이 스펙 우선 방식이 깃(Git) 네이티브 API 워크플로와 잘 어울리는 이유이기도 합니다: 스펙은 일반 텍스트 파일이므로, 계약에 대한 모든 변경 사항은 풀 리퀘스트에서 검토 가능한 차이(diff)로 나타납니다. 검토자는 누군가가 email 이름을 바꾸거나 필수 필드를 제거하기 전에 이를 확인할 수 있습니다.
Apidog에서 수행하기
Apidog는 스펙 우선 모드(Spec-First Mode)를 통해 이러한 모든 과정을 지원합니다. OpenAPI 파일을 내보내기로 취급하는 대신, 파일을 프로젝트로 취급합니다. YAML을 직접 편집하면 나머지 워크스페이스가 이를 따릅니다.

편집기에 /users 스펙을 작성하거나 붙여넣습니다. Apidog는 이를 파싱하고 즉시 두 작업에 대한 목 서버를 설정하므로, 프론트엔드가 이를 호출할 수 있습니다. 생성된 문서는 타이핑하는 동안 업데이트됩니다. 구현을 검증할 준비가 되면, 스펙의 작업을 실제 백엔드에 대한 테스트 케이스로 실행하고 응답이 스키마와 일치하는지 확인합니다.
이를 정직하게 유지하는 부분은 양방향 Git 동기화입니다. 스펙은 저장소에 존재하며, 변경 사항은 양방향으로 흐릅니다. 편집기에서 YAML을 편집하고 푸시하면 Apidog가 이를 감지합니다. Apidog에서 편집하면 변경 사항이 팀이 검토할 수 있는 커밋으로 저장됩니다. 계약은 동시에 두 곳에 존재하지 않습니다. 순수한 디자인 우선 접근 방식과 이것이 어떻게 비교되는지 더 깊이 이해하고 싶다면, Apidog의 스펙 우선 vs 디자인 우선을 참조하십시오.
스펙 우선 체크리스트
스펙이 구축 준비가 되었다고 간주하기 전에 다음을 확인하십시오:
- 스펙이 OpenAPI 스키마에 대해 오류 없이 유효성 검사를 통과합니다.
- 모든 엔드포인트는 성공 응답과 최소 하나의 오류 응답을 선언합니다.
- 공유된 형태는
components/schemas에 존재하며, 복사되지 않고$ref로 참조됩니다. - 필수 필드는
required로 표시되며, 형식(uuid,email,date-time)은 적용되는 곳에 설정됩니다. - 스펙 파일은 버전 관리에 커밋되며 풀 리퀘스트에서 검토됩니다.
- 스펙에서 목 서버가 실행되며, 프론트엔드가 이를 호출할 수 있습니다.
- 계약 테스트는 선언된 스키마에 대해 실제 응답을 확인합니다.
- 게시된 문서는 수동으로 유지 관리되는 사본 없이 동일한 파일에서 렌더링됩니다.
모든 항목이 확인되면, 팀은 세 가지 추측 대신 하나의 합의에 따라 병렬로 구축할 수 있습니다.
자주 묻는 질문
스펙 우선 API 개발은 디자인 우선과 동일한가요?
대체로 그렇습니다. "디자인 우선"과 "계약 우선"은 동일한 원칙을 설명합니다: 구현 전에 인터페이스를 작성하는 것입니다. "스펙 우선"은 시작하는 구체적인 산출물이 OpenAPI 스펙 파일이기 때문에 가장 문자 그대로의 이름입니다. 실제로는 이 용어들이 상호 교환적으로 사용됩니다.
YAML을 직접 작성해야 하나요?
아니요. 시각적 편집기에서 스펙을 작성하고 YAML을 생성하게 하거나, 선호한다면 YAML을 직접 작성할 수 있습니다. 핵심은 작성하는 형식이 아니라, 코드를 작성하기 전에 계약이 존재하고 합의된다는 점입니다. 많은 팀들이 시각적으로 초안을 작성하고 검토 중에 YAML에서 다듬는 방식을 혼합하여 사용합니다.
스펙과 코드가 서로 멀어지는 것을 어떻게 막을 수 있나요?
스펙을 진실의 원천으로 만들고 이를 강제합니다. 변경 사항이 diff로 검토되도록 스펙을 Git에 보관하십시오. 응답이 스키마와 일치하지 않을 때 빌드가 실패하도록 CI에서 계약 테스트를 실행하십시오. 양방향 동기화를 통해 어느 한쪽에서든 편집 내용이 일치하도록 유지되어 가장 흔한 불일치 원인을 제거할 수 있습니다.
스펙 우선 API 개발은 순서의 작은 변화가 결과에 큰 변화를 가져옵니다. 계약을 작성하고, 합의한 다음, 그에 맞춰 구축하세요. 전체 과정을 시도하고 싶다면, Apidog에서 스펙 우선 모드(Spec-First Mode)를 열고 자신의 저장소를 가리키세요.
