OPEN HYPER STEP
← 목록으로 (stack-analysis)
STACK-ANALYSIS · 51 / 90
stack-analysis
CHAPTER 51 / 90
읽기 약 2
FUNCTION

OpenAPI/Swagger 자동 문서화


핵심 개념

OpenAPI 3.1·zod-openapi·Swagger UI·CI 검증 — 문서 = 코드.

본문

OpenAPI 3.1 — zod-openapi

BASH📋 코드 (1줄)
pnpm add zod-openapi @asteasolutions/zod-to-openapi
TYPESCRIPT📋 코드 (22줄)
// schemas/post.ts
import { z } from 'zod';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
extendZodWithOpenApi(z);

export const PostSchema = z.object({
  id: z.string().openapi({ example: 'p_abc123' }),
  title: z.string().min(1).max(200).openapi({ example: '오늘의 글' }),
  content: z.string().openapi({ example: '본문...' }),
  authorId: z.string(),
  published: z.boolean(),
  createdAt: z.string().datetime(),
}).openapi('Post');

export const CreatePostSchema = PostSchema.pick({
  title: true, content: true,
}).openapi('CreatePost');

export const PostListSchema = z.object({
  items: z.array(PostSchema),
  nextCursor: z.string().nullable(),
}).openapi('PostList');

라우트 등록

TYPESCRIPT📋 코드 (66줄)
import { OpenAPIRegistry, OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi';

const registry = new OpenAPIRegistry();

registry.registerPath({
  method: 'get',
  path: '/posts',
  description: '게시물 목록 조회 (cursor 페이지네이션)',
  summary: '게시물 목록',
  tags: ['Posts'],
  request: {
    query: z.object({
      limit: z.coerce.number().int().min(1).max(100).default(20),
      cursor: z.string().optional(),
    }),
  },
  responses: {
    200: {
      description: '게시물 목록',
      content: { 'application/json': { schema: PostListSchema } },
    },
    401: {
      description: '인증 실패',
      content: { 'application/problem+json': { schema: ProblemSchema } },
    },
  },
});

registry.registerPath({
  method: 'post',
  path: '/posts',
  description: '새 게시물 생성',
  tags: ['Posts'],
  security: [{ bearerAuth: [] }],
  request: {
    body: { content: { 'application/json': { schema: CreatePostSchema } } },
  },
  responses: {
    201: { description: '생성됨', content: { 'application/json': { schema: PostSchema } } },
    400: { description: '검증 실패', content: { 'application/problem+json': { schema: ProblemSchema } } },
  },
});


registry.registerComponent('securitySchemes', 'bearerAuth', {
  type: 'http',
  scheme: 'bearer',
  bearerFormat: 'JWT',
});


// 문서 생성
const generator = new OpenApiGeneratorV31(registry.definitions);
const document = generator.generateDocument({
  openapi: '3.1.0',
  info: {
    title: 'My API',
    version: '1.0.0',
    description: '...',
  },
  servers: [{ url: 'https://api.example.com' }],
});


// 정적 파일 또는 동적 엔드포인트
fs.writeFileSync('openapi.json', JSON.stringify(document, null, 2));

Swagger UI 호스팅

TYPESCRIPT📋 코드 (16줄)
import swaggerUi from 'swagger-ui-express';

app.get('/openapi.json', (req, res) => res.json(document));
app.use('/docs', swaggerUi.serve, swaggerUi.setup(document, {
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'My API Docs',
}));


// 또는 Scalar (모던 UI)
import { apiReference } from '@scalar/express-api-reference';

app.use('/docs', apiReference({
  spec: { url: '/openapi.json' },
  theme: 'purple',
}));

검증 + 문서 = 같은 스키마

TYPESCRIPT📋 코드 (11줄)
// 라우트 핸들러 — Zod로 검증 + OpenAPI 자동 생성
router.post('/posts', asyncHandler(async (req, res) => {
  const data = CreatePostSchema.parse(req.body);  // 동일 스키마
  const post = await postService.create(req.user!.id, data);
  res.status(201).json(post);
}));


// → 검증 실패 = 400 RFC 7807
// → 성공 = 201 + PostSchema
// → 문서와 실제 동작 100% 일치

CI 검증

YAML📋 코드 (17줄)
# .github/workflows/api-docs.yml
- name: Generate OpenAPI
  run: pnpm generate:openapi

- name: Validate OpenAPI
  run: pnpm dlx @redocly/cli lint openapi.json

- name: Diff against main
  run: |
    git diff main openapi.json
    if [ $? -ne 0 ]; then
      echo "API spec changed - reviewer check required"
    fi

- name: Breaking change detection
  run: |
    pnpm dlx oasdiff breaking main:openapi.json HEAD:openapi.json

클라이언트 SDK 자동 생성

BASH📋 코드 (10줄)
# TypeScript
pnpm dlx openapi-typescript openapi.json -o ./generated/api.ts


# 또는 풀 SDK
pnpm dlx @hey-api/openapi-ts -i openapi.json -o ./generated -c @hey-api/client-fetch


# Python
pnpm dlx openapi-python-client generate --url openapi.json

다음 챕터

CH.52 "tRPC: 타입 안전 API의 미래".


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 코드의 API 문서화 부분을 분석해서
실전 분석 + 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

API 문서화 관련 인기 라이브러리/패턴 5개를
비교 분석해서 패턴 추출를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 프로젝트 전체에서 API 문서화
최적화 가능 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 백엔드 시장의
API 문서화 트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
OpenAPI/Swagger 자동 문서화 이 3가지만 확실히 잡으세요
1.Zod 스키마 = 검증 + OpenAPI 문서 — 단일 진실 공급원
2.Swagger UI/Scalar로 인터랙티브 문서 — 팀·외부 개발자 친화
3.CI에서 spec lint + breaking change 검출 — 자동 안전망


공유하기
진행도 51 / 90