infra
Platform

모듈 맵

[SW Eng] API와 계약 — REST·GraphQL·스키마로 서비스가 대화하는 법

0 / 38 완료

펼치기
0 / 38 완료0%

Sw-engineering · 19 / 38

[SW Eng] API와 계약 — REST·GraphQL·스키마로 서비스가 대화하는 법

REST/GraphQL·엔드포인트·요청/응답·직렬화·OpenAPI 계약·버전 관리를 PM·인프라 관점에서 정리하고, 계약이 흔들릴 때의 협업 비용을 다룹니다

🚨INCIDENT ALERT
HIGH

프론트 개발자가 화났습니다. "어제까지 응답에 있던 userName 필드가 오늘 사라졌어요. 화면이 다 깨졌습니다." 백엔드는 "아, name으로 바꿨는데요"라고 답합니다. 공지도, 버전도 없었습니다. 또 다른 회의에선 "그 API 응답이 어떻게 생겼죠?"를 두고 FE·BE가 서로 다른 그림을 그리고 있습니다. API는 서비스들이 대화하는 '계약'입니다. 이 계약이 명확하고 안정적이면 팀이 병렬로 빠르게 달리고, 흔들리면 서로의 작업이 끊임없이 깨집니다.

이번 챕터에서 배울 것
  • 1REST의 자원(경로)·행위(HTTP 메서드) 모델을 설명할 수 있다
  • 2API 계약(요청/응답 스키마)이 FE↔BE 병렬 개발을 가능케 함을 설명할 수 있다
  • 3REST와 GraphQL의 차이를 "고정 응답 vs 필드 선택"으로 구분할 수 있다
  • 4API breaking change를 버전·deprecated·공지로 안전하게 내는 법을 설명할 수 있다

REST — 자원과 행위

💡개념

경로는 '무엇을', 메서드는 '어떻게'

REST API는 자원(경로)행위(HTTP 메서드) 의 조합으로 표현합니다.

TEXT
GET    /orders        주문 목록 조회      (안전·멱등: 여러 번 호출해도 같음)
POST   /orders        새 주문 생성        (호출마다 새로 생김)
GET    /orders/42     42번 주문 조회
PATCH  /orders/42     42번 주문 일부 수정
DELETE /orders/42     42번 주문 삭제      (멱등: 여러 번 = 결과 같음)

요청/응답은 보통 JSON:
  요청 Body:  {"productId": 7, "qty": 2}
  응답 Body:  {"orderId": 42, "status": "created"}

핵심 규약: GET은 데이터를 바꾸지 않는다(안전), 같은 요청을 여러 번 해도 결과가 같아야 하는 것이 멱등성([[requirements-prd]]의 중복 처리와 연결). HTTP 상태코드(200/201/400/404/500…)로 결과를 알립니다 — 깊은 코드 해석은 [[glossary-observability]]·networking 트랙에서.

계약 — 먼저 합의하면 병렬로 달린다

💡개념

API 계약: FE와 BE가 동시에 일하게 하는 약속

[[dev-roles-collaboration]]에서 본 'FE↔BE 인터페이스'가 바로 API 계약입니다. 계약은 다음을 정합니다.

TEXT
계약(예: OpenAPI 명세):
  엔드포인트:  POST /orders
  요청 스키마:  { productId: number(필수), qty: number(필수, ≥1) }
  응답 스키마:  { orderId: number, status: "created"|"failed" }
  에러 형식:   { code: string, message: string }  (예: 400, 409)

계약을 먼저 합의하면:

  • FE는 그 계약으로 목(mock) 서버를 띄워 화면을 병렬 개발
  • BE는 그 계약에 맞춰 구현
  • 둘이 만나는 지점에서 어긋남이 최소화

도구: OpenAPI(Swagger) 명세로 계약을 코드처럼 관리하고, 스키마 검증(JSON Schema) 으로 요청/응답이 계약을 지키는지 자동 확인합니다. 계약이 문서로 고정되면 "그 API 어떻게 생겼죠?"라는 소모적 질문이 사라집니다.

REST vs GraphQL — 언제 무엇을
표준적 CRUD, 캐싱·단순함 중시REST엔드포인트별 고정 응답, HTTP 캐시 친화
화면마다 필요한 데이터 조합이 크게 다름(모바일·대시보드)GraphQL클라이언트가 필드 선택, over/under-fetch 완화
외부 공개 API·단순 연동REST생태계·도구 풍부, 진입장벽 낮음
실시간 양방향(채팅·알림)WebSocket/SSE 별도REST/GraphQL과 병행

계약 준수·변경 점검 — 직접 확인

1API 응답이 계약(스키마)과 일치하는지 확인

연동 문제나 화면 깨짐이 의심되면, 실제 응답을 계약과 대조합니다. 코드를 못 짜도 할 수 있는 점검입니다.

로컬 또는 서버
# 실제 응답 구조 확인
curl -s https://api.example.com/orders/42 | jq .

# 계약(OpenAPI)에 명시된 필드와 실제 응답 필드 대조
curl -s https://api.example.com/orders/42 | jq 'keys'
# 기대: ["orderId","status","items","createdAt"]
OUTPUT
$ curl -s .../orders/42 | jq 'keys'
["orderId", "name", "items"]      ← 계약엔 "userName"인데 실제는 "name"!
                                    + "status","createdAt" 누락
→ 계약과 응답 불일치. FE 화면 깨짐의 원인. 누가 언제 바꿨나 추적([[git-fundamentals]])
curl -s https://api.example.com/orders/42 | jq .
🔍실행 후 확인할 것
  • jq keys로 응답 필드 목록을 계약과 대조 — 계약에 있는데 응답에 없으면(필드 삭제/이름변경) breaking change. FE 깨짐의 직접 원인
  • HTTP 상태코드를 먼저 본다: 2xx면 성공인데 형식이 다른 것, 4xx면 요청 잘못, 5xx면 서버 장애 — 방향이 완전히 다르다([[glossary-observability]])
  • 같은 요청을 두 번 보냈을 때 POST가 주문을 2개 만들면 멱등성 미보장 → 중복 결제 위험. Idempotency-Key 적용 여부 확인
  • 응답 필드가 바뀌었으면 git에서 "언제 누가" 바꿨는지 추적해, 버전/공지 없이 낸 breaking change인지 확인([[semantic-versioning]])

상황: 백엔드가 정리 차원에서 응답 필드 userNamename으로 바꿨는데, 공지·버전 없이 배포돼 프론트엔드와 외부 연동사의 코드가 일제히 깨집니다.

원인: 계약을 깨는 변경(breaking change)을 통보·버전 없이 냈습니다. API 응답 형식은 클라이언트와의 계약인데, 한쪽이 임의로 바꾸면 그 형식에 의존하던 모든 곳이 무너집니다([[semantic-versioning]]).

진단:

로컬 터미널
# 계약(OpenAPI) diff 또는 응답 필드 변화 확인
git log -p -- openapi.yaml | grep -A2 -B2 "userName\|name"

해결: (1) 즉시 호환 복구 — 옛 필드(userName)를 유지하면서 새 필드(name)를 함께 제공(둘 다 응답). (2) 변경은 버전 분리(/v2) 또는 deprecated 표기 + 유예 기간 + 사전 공지로. (3) CI에 계약 호환성 검사(OpenAPI diff)를 넣어 breaking change가 게이트에서 잡히게([[cicd-pipeline]]). API는 '내 코드'가 아니라 '여러 팀·외부와의 계약'이라는 인식이 핵심입니다.

💼
실무 맥락
현업 패턴

인프라/플랫폼 관점에서 API 계약은 [[api-gateway-webhook]]·게이트웨이 설정, 버전 라우팅(/v1, /v2), 스키마 검증·레이트리밋의 기준이 됩니다. CI에 OpenAPI 호환성 검사를 넣어 breaking change를 머지 게이트에서 막는 것도 플랫폼팀의 역할입니다. PM은 API 계약을 'FE·BE·외부 연동사가 공유하는 합의서'로 관리해, 변경 시 영향 범위(누가 이 API를 쓰나)와 마이그레이션 일정을 조율합니다. 특히 외부에 공개된 API의 breaking change는 연동사 신뢰와 직결되므로, deprecated 정책과 공지 채널을 미리 갖춰야 합니다.

다음 모듈에서는 이런 서비스들이 환경에 흔들리지 않고 동작하도록 만드는 설계 원칙 — 12-Factor App을 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

REST API에서 'POST /orders'와 'GET /orders/42'의 의미 차이는?

Q2

API 계약(contract)이 'FE↔BE 합의'로 중요한 이유는?

Q3

GraphQL이 REST와 다른 핵심 특징은?

Q4

API에 'breaking change'를 낼 때 권장되는 방식은?

0 / 4 답변

이것도 배워보세요