API 문서화
규칙
- OpenAPI 3.1 스펙을 단일 진실 공급원으로 사용 — 코드에서 생성하고, 수동으로 작성하지 않음
- Zod 스키마를 OpenAPI로 변환:
zod-openapi 또는 @asteasolutions/zod-to-openapi 사용 — 한 번 정의하고 검증 및 문서화
- 대화형 문서: Scalar(현대적, 빠름) 또는 Swagger UI —
/docs 또는 /api-docs에서 제공
- 모든 엔드포인트에는 다음이 포함되어야 함: 요약, 설명, 요청 본문 스키마, 모든 응답 코드와 예제
- 모든 엔드포인트에 대한 예제 요청/응답 — 실제 데이터 사용,
"string"과 같은 플레이스홀더 사용 금지
- 버저닝 전략: 호환성이 깨지는 변경을 위해 URL 경로 사용(
/api/v1/, /api/v2/) — 헤더 버저닝보다 간단함
- 오류 응답: 모든 오류 형태를 일관되게 문서화 —
{ error: string, code: string, details?: object }
- 인증: 보안 스키마 섹션에서 인증 방식(Bearer 토큰, API 키) 문서화
- 엔드포인트를 리소스별로 그룹화:
/users, /products, /orders — 문서 UI에서 그룹화를 위해 태그 사용
패턴
import { z } from "zod";
import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
extendZodWithOpenApi(z);
const UserSchema = z.object({
id: z.string().uuid().openapi({ example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }),
name: z.string().openapi({ example: "Jane Smith" }),
email: z.string().email().openapi({ example: "[email protected]" }),
}).openapi("User");
const CreateUserSchema = UserSchema.omit({ id: true }).openapi("CreateUser");
registry.registerPath({
method: "post",
path: "/api/v1/users",
summary: "사용자 생성",
request: { body: { content: { "application/json": { schema: CreateUserSchema } } } },
responses: {
201: { description: "사용자 생성됨", content: { "application/json": { schema: UserSchema } } },
400: { description: "유효성 검사 오류" },
},
});
지양할 것
- OpenAPI YAML을 수동으로 작성하지 말 것 — Zod 스키마 또는 라우트 정의에서 생성
- 오류 응답 문서화를 누락하지 말 것 — 400, 401, 403, 404, 500 문서화
"string" 또는 0과 같은 일반적인 예제를 사용하지 말 것 — 실제 데이터의 형태를 보여주는 현실적인 값 사용
- 구현과 동떨어진 문서를 만들지 말 것 — 검증에 사용되는 동일한 스키마로 스펙 생성