MAKITTDocs

Schema Verification Guide

docs/api/SCHEMA_VERIFY.md

Schema Verification Guide

Shop API의 서버 DTO와 클라이언트 Zod 스키마 간 불일치를 자동 검출하는 도구.

사용법

# 전체 검증 pnpm --filter @makitt/api verify-schemas # 특정 리소스만 pnpm --filter @makitt/api verify-schemas -- --resource=blog.blog # 특정 도메인 전체 pnpm --filter @makitt/api verify-schemas -- --domain=checkout # 특정 액션만 pnpm --filter @makitt/api verify-schemas -- --resource=action:checkout.create # 서버 최신 스펙으로 검증 (shop-api 실행 중이어야 함) pnpm --filter @makitt/api verify-schemas -- --fresh # 조합 pnpm --filter @makitt/api verify-schemas -- --domain=blog --fresh pnpm --filter @makitt/api verify-schemas -- --resource=product.product --fresh

옵션

옵션설명예시
--resource=<key>특정 리소스 또는 액션만 검증--resource=blog.blog, --resource=action:auth.login
--domain=<id>특정 도메인 전체 검증--domain=product, --domain=checkout
--fresh검증 전 서버에서 OpenAPI JSON 최신화
--url=<url>--fresh 시 사용할 서버 URL--url=https://shop-api.dev.makitt.shop/v3/api-docs

선결 조건

docs/api/shop-api-openapi.json 파일이 존재해야 함. 두 가지 방법:

# 방법 1: --fresh 옵션 (서버 실행 중일 때) pnpm --filter @makitt/api verify-schemas -- --fresh # 방법 2: 스크립트 직접 실행 ./scripts/extract-openapi.sh

서버 안 바꿨으면 기존 커밋된 JSON으로 검증 가능 (서버 불필요).

리포트 읽는 법

Total: 64 | ✅ Pass: 0 | ⚠️ Warn: 38 | ❌ Fail: 12 | ⏭️ Skip: 14

❌ blog.blog
   Path: /shop/{shopId}/blogs/{blogId}
   Fields: Zod=20, OpenAPI=20
   ⚠️ [missing_in_zod] seo.metaTitle: Server sends but Zod does not define
   ❌ [missing_in_openapi] seo.title: Zod expects but server does not send

심각도

아이콘이슈의미영향
missing_in_openapiZod에 있지만 서버가 안 보냄HCS 바인딩 실패 — 해당 필드가 항상 undefined
type_mismatch타입이 다름런타임 타입 오류 가능
⚠️missing_in_zod서버가 보내지만 Zod에 없음Builder 자동완성에 안 뜸, HCS 바인딩 불가
⚠️nullable_mismatch서버는 null 가능인데 Zod는 required서버 @Schema 미지정 노이즈가 대부분
⏭️skip비교 불가z.any() 스키마 또는 OpenAPI 경로 없음

상태별 대응

상태대응
FAIL반드시 수정. 서버 DTO 변경 또는 Zod 스키마 수정
WARN (missing_in_zod)Zod에 필드 추가 권장 (HCS 바인딩에 필요하면)
WARN (nullable_mismatch)대부분 노이즈. 서버 @Schema(requiredMode = REQUIRED) 보강 시 해결
SKIPz.any() → 실제 스키마 정의하면 자동으로 검증 대상에 포함

새 리소스/액션 추가 시

리소스

resources/*.ts에서 apiPathapiMethod를 함께 넣으면 자동으로 검증 대상:

export const myResource: ResourceDefinition<typeof MySchema> = { key: 'myResource', displayName: '내 리소스', type: 'single', schema: MySchema, apiPath: '/shop/{shopId}/my-resources/{id}', // ← 이것만 추가 apiMethod: 'get', // ← 이것만 추가 fetcher: (shopId, params) => myApi.detail(shopId, params), };

액션

action-registry.ts에서 responseSchema + apiPath + apiMethod를 넣으면 검증 대상:

'myDomain.myAction': { schema: myInputSchema, responseSchema: MyResponseSchema, // ← 응답 스키마 apiPath: '/shop/{shopId}/my-resources', // ← 이것만 추가 apiMethod: 'post', // ← 이것만 추가 execute: async (params, context) => { ... }, },

apiPath를 안 넣으면 검증에서 스킵 (기존 동작 영향 없음).

검증 범위

비교 항목지원
1depth 필드명
nested object 필드 (seo.title)
array item 필드 (items[].name)
타입 비교 (string/number/boolean/object/array)
nullable/optional
z.any() 스키마⏭️ Skip

파일 구조

makitt-root/
├── scripts/extract-openapi.sh          # 서버 → JSON 추출
├── docs/api/
│   ├── shop-api-openapi.json           # 커밋된 OpenAPI 스펙
│   ├── schema-mismatch-report.md       # 불일치 리포트
│   └── SCHEMA_VERIFY.md               # 이 문서

makitt-client/packages/api/src/verify/
├── cli.ts                              # CLI 실행 진입점
├── openapi-utils.ts                    # OpenAPI JSON 파싱
├── schema-verify.ts                    # 비교 엔진 + 리포트
└── schema-verify.test.ts              # CI용 vitest 테스트

CI

pnpm --filter @makitt/api verify-schemas:ci

FAIL이 있으면 exit code 1로 실패.