스토리텔링 형식으로 업데이트되었습니다! 실무 사례와 함께 더 쉽게 이해할 수 있어요.
이미지 로딩 중...
AI Generated
2025. 11. 25. · 17 Views
OpenAPI/Swagger로 API 문서화 완벽 가이드
API 문서화의 표준인 OpenAPI와 Swagger를 활용하여 프론트엔드 개발자와 원활하게 협업하는 방법을 배웁니다. 스펙 작성부터 자동 문서 생성, 버전 관리까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.
목차
- OpenAPI 3.0 스펙 이해하기
- Swagger UI 설정과 커스터마이징
- 자동 문서 생성 도구
- API 스키마 정의 (Request/Response)
- 예제와 설명 추가하기
- 문서 버전 관리
1. OpenAPI 3.0 스펙 이해하기
김개발 씨는 새로운 프로젝트에 투입된 지 일주일째입니다. 프론트엔드 개발자 이프론트 씨가 슬랙으로 메시지를 보내왔습니다.
"저번에 말한 API 엔드포인트 정보 좀 주세요. 어떤 파라미터가 필요하고, 응답은 어떻게 오는지 모르겠어요." 김개발 씨는 노션에 대충 정리해둔 문서를 보내주었지만, 이내 또 다른 질문이 쏟아졌습니다.
OpenAPI 3.0은 REST API를 설명하는 표준 스펙입니다. 마치 건축물의 설계도면처럼, API가 어떤 엔드포인트를 가지고 있고, 어떤 데이터를 주고받는지 명확하게 정의합니다.
이 스펙을 따르면 프론트엔드와 백엔드 개발자가 같은 언어로 소통할 수 있습니다.
다음 코드를 살펴봅시다.
openapi: 3.0.3
info:
title: 쇼핑몰 API
description: 상품 및 주문 관리를 위한 REST API
version: 1.0.0
contact:
name: API 지원팀
email: api@example.com
servers:
- url: https://api.example.com/v1
description: 운영 서버
- url: https://dev-api.example.com/v1
description: 개발 서버
paths:
/products:
get:
summary: 상품 목록 조회
operationId: getProducts
responses:
'200':
description: 성공적으로 조회됨
김개발 씨는 입사 3개월 차 백엔드 개발자입니다. 오늘도 열심히 API를 만들었는데, 프론트엔드 팀에서 끊임없이 질문이 들어옵니다.
"이 API는 어떤 파라미터를 받나요?", "응답 형식이 어떻게 되나요?", "에러가 나면 어떤 코드가 오나요?" 선배 개발자 박시니어 씨가 다가와 말합니다. "API 문서화 제대로 안 해두면 매일 이렇게 질문 공세를 받게 돼요.
OpenAPI 스펙으로 문서를 작성해보는 게 어때요?" 그렇다면 OpenAPI란 정확히 무엇일까요? 쉽게 비유하자면, OpenAPI는 마치 식당의 메뉴판과 같습니다.
메뉴판에는 음식 이름, 가격, 재료, 조리 방법 등이 적혀 있어서 손님이 주문하기 전에 모든 정보를 알 수 있습니다. OpenAPI도 마찬가지로 API의 엔드포인트, 파라미터, 응답 형식 등 모든 정보를 한 곳에 정리해둡니다.
OpenAPI가 없던 시절에는 어땠을까요? 개발자들은 위키나 노션에 API 정보를 수동으로 작성했습니다.
문제는 코드가 변경될 때마다 문서도 함께 업데이트해야 하는데, 이 과정이 누락되기 일쑤였습니다. 결국 문서와 실제 API가 달라지는 상황이 빈번하게 발생했고, 이로 인한 버그와 커뮤니케이션 비용은 눈덩이처럼 불어났습니다.
바로 이런 문제를 해결하기 위해 OpenAPI 스펙이 등장했습니다. OpenAPI 3.0 문서는 크게 세 부분으로 구성됩니다.
첫째, info 섹션에는 API의 제목, 설명, 버전, 담당자 연락처 등 메타 정보가 들어갑니다. 둘째, servers 섹션에는 API가 배포된 서버 주소를 명시합니다.
개발 서버와 운영 서버를 구분해서 적어두면 환경별로 테스트하기 편리합니다. 셋째, paths 섹션에는 실제 API 엔드포인트들이 정의됩니다.
위의 코드를 살펴보겠습니다. 맨 위에 openapi: 3.0.3은 이 문서가 OpenAPI 3.0.3 버전 스펙을 따른다는 선언입니다.
info 섹션에서는 API의 이름을 "쇼핑몰 API"로 정하고, 버전은 1.0.0으로 시작합니다. servers 섹션에서는 운영 서버와 개발 서버 두 개의 URL을 등록했습니다.
실제 현업에서는 어떻게 활용할까요? 대부분의 기업에서는 API를 설계하는 단계에서부터 OpenAPI 문서를 작성합니다.
이를 API First 방식이라고 부릅니다. 먼저 스펙을 정의하고, 프론트엔드와 백엔드 개발자가 합의한 후에 구현을 시작하는 것입니다.
이렇게 하면 서로 다른 팀이 병렬로 개발을 진행할 수 있어 효율이 크게 높아집니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 OpenAPI 문서를 한 번 작성하고 방치하는 것입니다. 코드가 변경되면 문서도 반드시 함께 업데이트해야 합니다.
다행히 이 과정을 자동화하는 도구들이 많이 있으니, 뒤에서 자세히 알아보겠습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 조언을 듣고 OpenAPI 스펙을 공부하기 시작한 김개발 씨는 고개를 끄덕였습니다. "아, 이렇게 표준화된 형식으로 작성하면 모두가 같은 문서를 보고 이해할 수 있겠네요!"
실전 팁
💡 - OpenAPI 문서는 YAML 또는 JSON 형식으로 작성할 수 있으며, YAML이 가독성이 더 좋습니다
- VS Code의 OpenAPI 확장 프로그램을 설치하면 문법 검사와 자동 완성을 지원받을 수 있습니다
2. Swagger UI 설정과 커스터마이징
김개발 씨는 OpenAPI 스펙 파일을 작성했습니다. 그런데 이 YAML 파일을 프론트엔드 개발자에게 그대로 보내도 될까요?
이프론트 씨는 "저 YAML 파일 읽기 힘든데, 보기 좋게 정리된 문서는 없나요?"라고 물었습니다. 바로 이때 필요한 것이 Swagger UI입니다.
Swagger UI는 OpenAPI 스펙 파일을 웹 브라우저에서 보기 좋게 렌더링해주는 도구입니다. 마치 마크다운 파일을 예쁜 웹페이지로 변환해주는 것처럼, 딱딱한 YAML 파일을 인터랙티브한 API 문서로 바꿔줍니다.
게다가 문서에서 바로 API를 테스트해볼 수도 있습니다.
다음 코드를 살펴봅시다.
// Express.js에서 Swagger UI 설정하기
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
const app = express();
// OpenAPI 스펙 파일 로드
const swaggerDocument = YAML.load('./openapi.yaml');
// Swagger UI 커스터마이징 옵션
const options = {
customCss: '.swagger-ui .topbar { display: none }',
customSiteTitle: '쇼핑몰 API 문서',
customfavIcon: '/favicon.ico',
swaggerOptions: {
persistAuthorization: true,
displayRequestDuration: true
}
};
// /api-docs 경로에 Swagger UI 마운트
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
app.listen(3000, () => console.log('API 문서: http://localhost:3000/api-docs'));
김개발 씨는 OpenAPI 스펙 파일을 완성했습니다. 그런데 이 YAML 파일을 슬랙에 공유했더니, 프론트엔드 개발자들의 반응이 시큰둥합니다.
"이거 읽기 너무 불편해요. 웹페이지 형태로 볼 수 없나요?" 박시니어 씨가 웃으며 말합니다.
"Swagger UI라는 게 있어요. OpenAPI 파일을 예쁜 웹 문서로 변환해주고, 거기서 바로 API 테스트도 할 수 있어요." 그렇다면 Swagger UI는 어떻게 동작할까요?
쉽게 비유하자면, Swagger UI는 마치 번역가와 같습니다. 개발자가 작성한 기술적인 스펙 문서를 누구나 이해할 수 있는 시각적인 형태로 번역해줍니다.
엔드포인트별로 깔끔하게 정리되고, 파라미터와 응답 예시도 한눈에 볼 수 있습니다. Swagger UI가 없다면 어떻게 될까요?
개발자들은 API 문서를 직접 HTML로 만들거나, 노션 같은 도구에 수동으로 작성해야 합니다. 문제는 API가 변경될 때마다 두 곳을 모두 수정해야 한다는 것입니다.
시간이 지나면 스펙 파일과 문서 페이지가 서로 달라지는 상황이 발생하기 마련입니다. 위의 코드를 살펴보겠습니다.
먼저 swagger-ui-express와 yamljs 패키지를 import합니다. swagger-ui-express는 Express.js에서 Swagger UI를 쉽게 사용할 수 있게 해주는 미들웨어이고, yamljs는 YAML 파일을 JavaScript 객체로 파싱해줍니다.
YAML.load() 함수로 앞서 작성한 openapi.yaml 파일을 읽어옵니다. 이 파일이 Swagger UI의 데이터 소스가 됩니다.
options 객체에서는 Swagger UI의 외관과 동작을 커스터마이징합니다. customCss로 상단 바를 숨기고, customSiteTitle로 브라우저 탭에 표시될 제목을 지정합니다.
swaggerOptions의 persistAuthorization은 새로고침해도 인증 토큰이 유지되게 하고, displayRequestDuration은 API 호출 시간을 표시해줍니다. 마지막으로 **app.use()**로 /api-docs 경로에 Swagger UI를 마운트합니다.
이제 브라우저에서 http://localhost:3000/api-docs에 접속하면 예쁜 API 문서를 볼 수 있습니다. 실제 현업에서는 어떻게 활용할까요?
많은 기업에서 Swagger UI를 내부 개발자 포털로 활용합니다. 회사 로고를 넣고, 컬러 테마를 맞추고, 각 API에 대한 추가 설명을 덧붙입니다.
특히 "Try it out" 기능은 프론트엔드 개발자들이 백엔드 개발자에게 일일이 물어보지 않고도 API 동작을 직접 확인할 수 있어 매우 유용합니다. 하지만 주의할 점도 있습니다.
운영 환경에서 Swagger UI를 외부에 노출하면 보안 위험이 있습니다. API의 모든 엔드포인트와 파라미터가 공개되기 때문입니다.
따라서 인증이 필요하게 하거나, 내부 네트워크에서만 접근 가능하도록 설정하는 것이 좋습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
Swagger UI를 설정하고 팀에 공유했더니, 이프론트 씨가 매우 기뻐합니다. "와, 이제 여기서 바로 테스트해볼 수 있네요!
더 이상 Postman으로 일일이 요청 안 만들어도 되겠어요."
실전 팁
💡 - 운영 환경에서는 Swagger UI 접근에 기본 인증(Basic Auth)을 추가하는 것이 좋습니다
- Docker 환경에서는 swagger-ui 공식 이미지를 사용하면 별도 서버 없이도 문서를 호스팅할 수 있습니다
3. 자동 문서 생성 도구
김개발 씨는 문득 걱정이 됩니다. "API가 100개가 넘는데, 이걸 전부 수동으로 OpenAPI 스펙에 작성하라고요?" 실제로 대규모 프로젝트에서 모든 API를 수동으로 문서화하는 것은 현실적으로 불가능에 가깝습니다.
다행히 코드에서 자동으로 문서를 생성해주는 도구들이 있습니다.
자동 문서 생성 도구는 소스 코드의 데코레이터나 주석을 분석하여 OpenAPI 스펙을 자동으로 만들어줍니다. 마치 소설가가 원고를 쓰면 편집자가 자동으로 목차를 만들어주는 것과 같습니다.
NestJS의 @nestjs/swagger, Express의 swagger-jsdoc 등이 대표적입니다.
다음 코드를 살펴봅시다.
// NestJS에서 자동 문서 생성 설정
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Swagger 문서 설정
const config = new DocumentBuilder()
.setTitle('쇼핑몰 API')
.setDescription('상품 및 주문 관리 API')
.setVersion('1.0')
.addBearerAuth() // JWT 인증 추가
.addTag('products', '상품 관련 API')
.addTag('orders', '주문 관련 API')
.build();
// 문서 생성 및 설정
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document);
await app.listen(3000);
}
bootstrap();
김개발 씨는 고민에 빠졌습니다. 프로젝트에는 이미 200개가 넘는 API 엔드포인트가 있고, 매주 새로운 API가 추가되고 있습니다.
이 모든 것을 수동으로 OpenAPI 스펙에 작성하려면 며칠이 걸릴지 모릅니다. 게다가 코드가 변경될 때마다 문서도 함께 수정해야 합니다.
박시니어 씨가 해결책을 제시합니다. "자동 문서 생성 도구를 사용하면 돼요.
코드에 데코레이터만 달아두면 알아서 문서가 만들어져요." 그렇다면 자동 문서 생성은 어떻게 동작할까요? 쉽게 비유하자면, 자동 문서 생성은 마치 회의록 자동 작성 서비스와 같습니다.
회의에서 나눈 대화를 녹음해두면, AI가 알아서 핵심 내용을 정리해 문서로 만들어줍니다. 마찬가지로 코드에 특정 표시(데코레이터)만 달아두면, 도구가 알아서 API 문서를 생성합니다.
수동으로 문서를 작성할 때의 문제점은 무엇일까요? 첫째, 시간이 너무 많이 걸립니다.
둘째, 코드와 문서가 따로 존재하기 때문에 동기화가 어렵습니다. 코드를 수정하고 문서 업데이트를 깜빡하면, 문서는 거짓말을 하게 됩니다.
이런 문서는 없느니만 못합니다. 위의 코드를 살펴보겠습니다.
NestJS에서는 @nestjs/swagger 패키지를 사용합니다. DocumentBuilder를 통해 API 문서의 기본 정보를 설정합니다.
setTitle과 setDescription으로 제목과 설명을 지정하고, setVersion으로 API 버전을 명시합니다. **addBearerAuth()**는 JWT 토큰 인증을 문서에 추가합니다.
이렇게 하면 Swagger UI에서 토큰을 입력하고 인증이 필요한 API를 테스트할 수 있습니다. **addTag()**로는 API를 카테고리별로 그룹화합니다.
**SwaggerModule.createDocument()**가 핵심입니다. 이 함수가 애플리케이션의 모든 컨트롤러와 DTO를 스캔하여 OpenAPI 문서를 자동 생성합니다.
마지막으로 **SwaggerModule.setup()**으로 /api-docs 경로에 Swagger UI를 마운트합니다. 실제 현업에서는 어떻게 활용할까요?
대부분의 팀에서는 CI/CD 파이프라인에 문서 생성을 포함시킵니다. 코드가 머지되면 자동으로 최신 문서가 배포됩니다.
일부 팀은 PR 단계에서 문서 변경 사항을 리뷰하기도 합니다. OpenAPI 스펙 파일을 git에 커밋해두면 변경 이력도 추적할 수 있습니다.
하지만 주의할 점도 있습니다. 자동 생성에만 의존하면 문서의 품질이 떨어질 수 있습니다.
도구가 코드에서 추출할 수 있는 정보에는 한계가 있기 때문입니다. 예를 들어, "이 API는 왜 필요한가"나 "어떤 상황에서 사용하는가" 같은 맥락 정보는 개발자가 직접 작성해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 자동 문서 생성 도구를 도입한 후, 김개발 씨는 한결 마음이 편해졌습니다.
"이제 코드만 잘 작성하면 문서는 자동으로 따라오니까, 문서 업데이트를 깜빡할 걱정이 없어졌어요!"
실전 팁
💡 - Express.js를 사용한다면 swagger-jsdoc 패키지를 활용하여 JSDoc 주석에서 문서를 생성할 수 있습니다
- 자동 생성된 문서도 정기적으로 검토하여 부족한 설명을 보완하는 것이 좋습니다
4. API 스키마 정의 (Request/Response)
이프론트 씨가 다시 슬랙으로 메시지를 보냅니다. "API 응답에 어떤 필드가 있는지는 알겠는데, 각 필드의 타입이 뭔가요?
userId가 문자열인가요, 숫자인가요?" 엔드포인트 목록만으로는 부족합니다. 요청과 응답의 정확한 데이터 구조, 즉 스키마를 정의해야 합니다.
API 스키마는 요청(Request)과 응답(Response)의 데이터 구조를 정의한 것입니다. 마치 택배 상자에 붙이는 내용물 명세서처럼, 어떤 데이터가 어떤 형태로 들어있는지 명확하게 알려줍니다.
타입, 필수 여부, 제약 조건 등을 포함하여 프론트엔드와 백엔드가 정확히 같은 기대를 갖게 합니다.
다음 코드를 살펴봅시다.
// NestJS DTO로 스키마 정의하기
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsNumber, IsOptional, Min, Max } from 'class-validator';
// 요청 DTO 정의
export class CreateProductDto {
@ApiProperty({ description: '상품명', example: '무선 키보드' })
@IsString()
name: string;
@ApiProperty({ description: '가격 (원)', minimum: 0, example: 59000 })
@IsNumber()
@Min(0)
price: number;
@ApiPropertyOptional({ description: '상품 설명', example: '인체공학적 설계' })
@IsOptional()
@IsString()
description?: string;
}
// 응답 DTO 정의
export class ProductResponseDto {
@ApiProperty({ description: '상품 ID', example: 1 })
id: number;
@ApiProperty({ description: '상품명', example: '무선 키보드' })
name: string;
@ApiProperty({ description: '생성일시', example: '2024-01-15T09:00:00Z' })
createdAt: Date;
}
김개발 씨가 만든 API 문서를 보던 이프론트 씨가 또 질문합니다. "상품 생성 API에 price 필드가 있는데, 이게 문자열인가요 숫자인가요?
소수점은 허용되나요? 음수도 보낼 수 있나요?" 엔드포인트만 나열해서는 부족합니다.
데이터의 정확한 구조와 제약 조건을 알려줘야 합니다. API 스키마란 정확히 무엇일까요?
쉽게 비유하자면, 스키마는 마치 입사 지원서 양식과 같습니다. 양식에는 "이름(필수, 한글 10자 이내)", "나이(필수, 숫자)", "자기소개(선택, 500자 이내)" 같은 규칙이 적혀 있습니다.
지원자는 이 양식을 보고 정확히 어떤 형태로 정보를 작성해야 하는지 알 수 있습니다. 스키마 없이 개발하면 어떤 문제가 생길까요?
프론트엔드 개발자가 price 필드에 "59,000원"이라는 문자열을 보냈는데, 백엔드에서는 숫자 59000을 기대하고 있었다면 어떻게 될까요? 서버는 에러를 반환하고, 프론트엔드 개발자는 당황하며 백엔드 개발자에게 물어봐야 합니다.
이런 사소한 불일치가 수십 번 반복되면 프로젝트 전체가 지연됩니다. 위의 코드를 살펴보겠습니다.
@ApiProperty 데코레이터는 Swagger 문서에 표시될 정보를 정의합니다. description으로 필드 설명을, example로 예시값을 지정합니다.
minimum이나 maximum으로 값의 범위도 명시할 수 있습니다. @ApiPropertyOptional은 선택적 필드임을 나타냅니다.
필수가 아닌 필드는 이 데코레이터를 사용하면 Swagger UI에서 "(optional)"이라고 표시됩니다. class-validator의 데코레이터들은 실제 런타임에 유효성 검사를 수행합니다.
@IsString()은 문자열인지, @IsNumber()는 숫자인지, @Min(0)은 0 이상인지 검사합니다. 이렇게 하면 문서에 적힌 대로 유효성 검사가 자동으로 이루어집니다.
응답 DTO도 마찬가지입니다. ProductResponseDto를 정의해두면 프론트엔드 개발자는 응답에 어떤 필드가 포함되는지 정확히 알 수 있습니다.
id가 숫자이고, createdAt이 ISO 형식의 날짜 문자열이라는 것을 문서만 보고도 파악할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?
많은 팀에서 OpenAPI 스키마를 기반으로 프론트엔드의 타입 정의를 자동 생성합니다. openapi-typescript 같은 도구를 사용하면 OpenAPI 스펙에서 TypeScript 타입을 추출할 수 있습니다.
이렇게 하면 프론트엔드와 백엔드가 같은 타입 정의를 공유하게 되어 불일치 문제를 원천 차단할 수 있습니다. 하지만 주의할 점도 있습니다.
스키마를 너무 느슨하게 정의하면 문서의 가치가 떨어집니다. 예를 들어 모든 필드를 any 타입으로 정의하거나, 제약 조건을 명시하지 않으면 프론트엔드 개발자는 여전히 추측에 의존해야 합니다.
가능한 한 구체적으로 타입과 제약 조건을 명시하세요. 다시 김개발 씨의 이야기로 돌아가 봅시다.
스키마를 꼼꼼히 정의한 후, 이프론트 씨의 질문이 눈에 띄게 줄었습니다. "이제 문서만 보면 다 알 수 있어요.
덕분에 작업 속도가 훨씬 빨라졌어요!"
실전 팁
💡 - 예시값(example)은 실제로 사용 가능한 값을 넣어야 프론트엔드 개발자가 테스트하기 편합니다
- enum 타입은 반드시 가능한 모든 값을 명시하여 프론트엔드에서 하드코딩 실수를 방지하세요
5. 예제와 설명 추가하기
API 스키마를 정의했지만, 이프론트 씨는 여전히 헷갈려합니다. "문서대로 요청을 보내면 어떤 응답이 오는지 실제 예시가 있으면 좋겠어요.
그리고 에러가 났을 때는 어떤 응답이 오나요?" 좋은 API 문서는 단순한 스펙 나열이 아니라, 실제 사용 시나리오를 보여줘야 합니다.
예제와 설명은 API 문서의 품질을 결정짓는 핵심 요소입니다. 마치 요리 레시피에 완성 사진이 있어야 따라 만들기 쉬운 것처럼, API 문서에도 요청/응답의 실제 예시가 있어야 개발자가 쉽게 이해하고 활용할 수 있습니다.
성공 케이스뿐 아니라 에러 케이스의 예시도 포함해야 합니다.
다음 코드를 살펴봅시다.
// 컨트롤러에 예제와 설명 추가하기
import { Controller, Post, Body, Get, Param } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger';
@ApiTags('products')
@Controller('products')
export class ProductsController {
@Post()
@ApiOperation({
summary: '상품 생성',
description: '새로운 상품을 등록합니다. 상품명과 가격은 필수입니다.'
})
@ApiBody({
type: CreateProductDto,
examples: {
basic: {
summary: '기본 상품',
value: { name: '무선 마우스', price: 35000 }
},
withDescription: {
summary: '설명 포함',
value: { name: '기계식 키보드', price: 89000, description: '청축, RGB 백라이트' }
}
}
})
@ApiResponse({ status: 201, description: '상품 생성 성공', type: ProductResponseDto })
@ApiResponse({ status: 400, description: '잘못된 요청', schema: {
example: { statusCode: 400, message: ['price must be a positive number'], error: 'Bad Request' }
}})
@ApiResponse({ status: 401, description: '인증 실패' })
create(@Body() dto: CreateProductDto) { /* ... */ }
}
김개발 씨는 열심히 API 문서를 작성했습니다. 엔드포인트도 있고, 스키마도 정의했습니다.
그런데 이프론트 씨가 말합니다. "문서는 있는데, 실제로 어떻게 사용하는지 감이 안 잡혀요.
예시가 있으면 좋겠어요." 박시니어 씨가 조언합니다. "좋은 문서는 읽는 사람 입장에서 작성해야 해요.
추상적인 스펙보다 구체적인 예시가 훨씬 이해하기 쉽거든요." 예제와 설명은 왜 중요할까요? 쉽게 비유하자면, 예제 없는 API 문서는 마치 그림 없는 요리책과 같습니다.
레시피에 "소금 적당량"이라고만 적혀 있으면 초보 요리사는 당황합니다. "적당량이 얼마죠?" 하지만 "소금 1/2 티스푼 (약 2.5g)"이라고 구체적으로 적혀 있고, 완성 사진이 있다면 누구나 따라 할 수 있습니다.
예제가 없으면 어떤 일이 벌어질까요? 프론트엔드 개발자는 문서의 스키마를 보고 나름대로 요청을 구성합니다.
그런데 응답 형식이 예상과 다릅니다. "id가 문자열로 오는 거였어요?
숫자인 줄 알았는데..." 이런 시행착오가 반복되면 개발 속도가 크게 떨어집니다. 위의 코드를 살펴보겠습니다.
@ApiOperation의 summary와 description으로 API의 목적과 상세 설명을 작성합니다. summary는 Swagger UI의 API 목록에 표시되는 한 줄 설명이고, description은 펼쳤을 때 보이는 상세 설명입니다.
@ApiBody의 examples 속성이 핵심입니다. 여러 개의 예시를 등록할 수 있습니다.
basic은 필수 필드만 포함한 가장 간단한 요청이고, withDescription은 선택 필드까지 포함한 요청입니다. Swagger UI에서 드롭다운으로 예시를 선택할 수 있어 매우 편리합니다.
@ApiResponse로는 다양한 응답 케이스를 문서화합니다. 성공 케이스(201)뿐 아니라 에러 케이스(400, 401)도 포함합니다.
특히 400 에러의 경우 실제로 어떤 형태의 에러 메시지가 반환되는지 예시를 보여주면, 프론트엔드에서 에러 처리 로직을 작성하기 훨씬 수월해집니다. 실제 현업에서는 어떻게 활용할까요?
우수한 팀에서는 "황금 경로(Golden Path)" 예시와 "에러 경로(Error Path)" 예시를 모두 문서화합니다. 예를 들어, 결제 API라면 정상 결제 성공, 카드 한도 초과, 유효하지 않은 카드 번호, 네트워크 오류 등 다양한 시나리오의 응답 예시를 제공합니다.
이렇게 하면 프론트엔드에서 모든 케이스에 대한 UI를 미리 준비할 수 있습니다. 하지만 주의할 점도 있습니다.
예시에 민감한 정보를 넣지 않도록 주의하세요. 실제 사용자 이메일이나 전화번호, 실제 API 키 등을 예시로 넣으면 보안 문제가 발생할 수 있습니다.
항상 가상의 데이터를 사용하세요. 다시 김개발 씨의 이야기로 돌아가 봅시다.
예제를 풍부하게 추가한 후, 이프론트 씨는 만족스럽게 말합니다. "이제 문서만 보고도 API를 어떻게 사용해야 하는지 바로 알겠어요.
질문할 게 거의 없어졌어요!"
실전 팁
💡 - 예시 데이터는 실제 비즈니스 시나리오를 반영하면 더 이해하기 쉽습니다 (예: 쇼핑몰이면 실제 상품명 사용)
- 에러 응답의 예시는 프론트엔드의 에러 핸들링 로직 작성에 필수적이니 반드시 포함하세요
6. 문서 버전 관리
서비스가 성장하면서 API도 진화합니다. 김개발 씨는 기존 API를 개선해야 하는데 고민입니다.
"응답 형식을 바꾸고 싶은데, 이미 이 API를 사용하는 모바일 앱이 있어요. 기존 앱이 망가지면 안 되는데..." API 문서의 버전 관리는 이런 상황에서 필수적입니다.
문서 버전 관리는 API의 변경 이력을 추적하고, 여러 버전의 API를 동시에 지원할 수 있게 해줍니다. 마치 도서관에서 책의 1판, 2판을 모두 보관하는 것처럼, 이전 버전을 사용하는 클라이언트와 새 버전을 사용하는 클라이언트를 동시에 지원할 수 있습니다.
다음 코드를 살펴봅시다.
// 버전별 API 문서 설정
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { INestApplication } from '@nestjs/common';
export function setupSwagger(app: INestApplication) {
// v1 API 문서
const v1Config = new DocumentBuilder()
.setTitle('쇼핑몰 API v1')
.setDescription('v1 API - 2024년 3월 지원 종료 예정')
.setVersion('1.0')
.addServer('/api/v1')
.build();
const v1Document = SwaggerModule.createDocument(app, v1Config, {
include: [ProductsV1Module, OrdersV1Module] // v1 모듈만 포함
});
SwaggerModule.setup('api-docs/v1', app, v1Document);
// v2 API 문서
const v2Config = new DocumentBuilder()
.setTitle('쇼핑몰 API v2')
.setDescription('v2 API - 현재 권장 버전')
.setVersion('2.0')
.addServer('/api/v2')
.build();
const v2Document = SwaggerModule.createDocument(app, v2Config, {
include: [ProductsV2Module, OrdersV2Module] // v2 모듈만 포함
});
SwaggerModule.setup('api-docs/v2', app, v2Document);
}
김개발 씨는 난감한 상황에 처했습니다. 상품 API의 응답 형식을 개선해야 하는데, 이미 출시된 모바일 앱이 현재 형식에 의존하고 있습니다.
응답 형식을 바꾸면 기존 앱이 망가지고, 바꾸지 않으면 새로운 요구사항을 충족할 수 없습니다. 박시니어 씨가 해결책을 제시합니다.
"API 버전 관리를 도입해야 할 때가 됐네요. v1은 유지하면서 v2를 새로 만드는 거예요." API 버전 관리란 정확히 무엇일까요?
쉽게 비유하자면, 버전 관리는 마치 소프트웨어 업데이트와 같습니다. 스마트폰의 iOS 17이 나왔다고 해서 iOS 16 사용자의 앱이 갑자기 작동을 멈추면 안 됩니다.
일정 기간 동안은 두 버전을 모두 지원하면서, 사용자들에게 업그레이드할 시간을 줍니다. API도 마찬가지입니다.
버전 관리 없이 API를 변경하면 어떻게 될까요? 서버에서 응답 형식을 바꾸는 순간, 이전 형식을 기대하던 모든 클라이언트가 오작동합니다.
모바일 앱 사용자들은 앱이 갑자기 망가진 것처럼 느끼고, 앱스토어에 1점 리뷰가 쏟아집니다. 이런 사태를 "Breaking Change(호환성이 깨지는 변경)"라고 부르며, 반드시 피해야 합니다.
위의 코드를 살펴보겠습니다. DocumentBuilder를 사용해 v1과 v2 두 개의 설정을 각각 만듭니다.
v1의 description에는 "2024년 3월 지원 종료 예정"이라고 명시하여 사용자들에게 마이그레이션을 유도합니다. v2의 description에는 "현재 권장 버전"이라고 표시합니다.
**SwaggerModule.createDocument()**의 include 옵션이 핵심입니다. v1 문서에는 ProductsV1Module과 OrdersV1Module만, v2 문서에는 ProductsV2Module과 OrdersV2Module만 포함시킵니다.
이렇게 하면 각 버전의 문서에 해당 버전의 API만 표시됩니다. 마지막으로 **SwaggerModule.setup()**에서 각각 다른 경로를 지정합니다.
/api-docs/v1과 /api-docs/v2로 분리하여 버전별로 독립적인 문서 페이지를 제공합니다. 실제 현업에서는 어떻게 활용할까요?
대부분의 기업에서는 최소 23개 버전을 동시에 유지합니다. 새 버전이 나오면 이전 버전에 "Deprecated(지원 중단 예정)" 표시를 하고, 6개월1년 정도의 유예 기간을 둡니다.
이 기간 동안 클라이언트들은 새 버전으로 마이그레이션할 시간을 갖습니다. AWS, Google, Stripe 같은 대형 서비스들도 모두 이런 방식을 따릅니다.
하지만 주의할 점도 있습니다. 버전이 너무 많아지면 유지보수 비용이 기하급수적으로 증가합니다.
v1, v2, v3, v4를 모두 유지하면서 버그를 수정하거나 보안 패치를 적용하려면 네 배의 작업이 필요합니다. 따라서 오래된 버전은 적절한 시점에 종료해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 버전 관리를 도입한 후, 김개발 씨는 안심하고 새로운 기능을 개발할 수 있게 되었습니다.
"기존 앱은 v1을 계속 사용하고, 새 앱은 v2를 사용하면 되니까 훨씬 유연해졌어요!"
실전 팁
💡 - API 버전은 URL 경로(/api/v1)나 헤더(Accept: application/vnd.api+json;version=1)로 구분할 수 있으며, URL 방식이 더 직관적입니다
- Deprecated API는 응답 헤더에 Deprecation 정보를 포함시켜 클라이언트에 알리는 것이 좋습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
효과적인 API 문서 작성법 완벽 가이드
API 문서는 개발자와 개발자 사이의 가장 중요한 소통 수단입니다. 이 가이드에서는 좋은 API 문서가 갖춰야 할 조건부터 Getting Started, 엔드포인트 설명, 에러 코드 문서화, 인증 가이드, 변경 이력 관리까지 체계적으로 배워봅니다.
예외 처리와 로깅 전략 완벽 가이드
초급 개발자를 위한 예외 처리와 로깅 전략 가이드입니다. Try-Catch부터 Sentry까지, 실무에서 바로 적용할 수 있는 에러 관리 기법을 단계별로 설명합니다.
일관된 에러 응답 설계 완벽 가이드
API 개발에서 가장 중요하면서도 간과하기 쉬운 에러 응답 설계를 다룹니다. 클라이언트와 서버가 명확하게 소통할 수 있는 표준화된 에러 응답 체계를 구축하는 방법을 배웁니다.
Vite 라이브러리 모드로 패키지 빌드하기 완벽 가이드
Vite의 라이브러리 모드를 활용하여 재사용 가능한 패키지를 빌드하는 방법을 배웁니다. lib 모드 설정부터 다양한 모듈 포맷 생성, TypeScript 선언 파일까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.
GraphQL 기초와 REST 비교 완벽 가이드
GraphQL의 핵심 개념부터 REST API와의 차이점까지 초급 개발자가 알아야 할 모든 것을 다룹니다. 실무에서 언제 GraphQL을 선택해야 하는지 명확하게 이해할 수 있습니다.