Skip to main content
SonamuλŠ” Zodλ₯Ό μ‚¬μš©ν•˜μ—¬ TypeScript νƒ€μž…μ„ λŸ°νƒ€μž„μ—μ„œλ„ κ²€μ¦ν•©λ‹ˆλ‹€. 이 λ¬Έμ„œλŠ” Zod validation의 λͺ¨λ“  κΈ°λŠ₯κ³Ό νŒ¨ν„΄μ„ μ„€λͺ…ν•©λ‹ˆλ‹€.

API HTTP validator μ΅œμ ν™”

SonamuλŠ” REST μš”μ²­μ˜ μ΅œμ’… fastifyCaster validatorλ₯Ό handler 수λͺ… λ™μ•ˆ ν•œ 번만 λ§Œλ“­λ‹ˆλ‹€. 이 μΊμ‹œλŠ” κΈ°λ³Έ λ™μž‘μ΄λ©° 별도 섀정이 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. zod-compilerλŠ” κ·Έ μ΅œμ’… validatorλ₯Ό μΆ”κ°€λ‘œ μ»΄νŒŒμΌν•˜λŠ” opt-in κΈ°λŠ₯μž…λ‹ˆλ‹€.

μ„€μ •

sonamu.config.ts
  • 섀정이 μ—†κ±°λ‚˜ zodCompiler: false이면 cached plain Zodλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
  • jitλŠ” μž₯κΈ° μ‹€ν–‰ Node.js μ„œλ²„μ— μ ν•©ν•©λ‹ˆλ‹€. μ„œλ²„κ°€ routeλ₯Ό μ€€λΉ„ν•  λ•Œ eager compileν•˜λ©°, μ»΄νŒŒμΌμ— μ‹€νŒ¨ν•˜λ©΄ 첫 μš”μ²­μ΄ μ•„λ‹ˆλΌ μ„œλ²„ μ‹œμž‘μ΄ μ‹€νŒ¨ν•©λ‹ˆλ‹€.
  • aotλŠ” pnpm sonamu build apiμ—μ„œ 생성 registry만 μ»΄νŒŒμΌν•©λ‹ˆλ‹€. 개발 μ„œλ²„λŠ” 같은 μ„€μ •μ—μ„œλ„ cached plain Zodλ₯Ό μ‚¬μš©ν•˜λ©°, ν”„λ‘œλ•μ…˜ μ‹œμž‘ μ‹œ registry fingerprint와 route coverageλ₯Ό ν™•μΈν•©λ‹ˆλ‹€.
  • Webκ³Ό Expo compiler target은 아직 μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ©° 후속 μž‘μ—…μœΌλ‘œ λ―Έλ£Ήλ‹ˆλ‹€.
  • 이번 API μ „μš© λ‹¨κ³„μ—μ„œλŠ” validation.zodCompiler.api만 μ„€μ •ν•  수 있고, validation.zodCompiler.targetsλŠ” 였λ₯˜λ‘œ κ±°λΆ€ν•©λ‹ˆλ‹€.
JITκ°€ μ‚¬μš©ν•˜λŠ” runtime μ˜μ‘΄μ„±μ€ Sonamu에 ν¬ν•¨λ˜μ–΄ μžˆμœΌλ―€λ‘œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— λ”°λ‘œ μ„€μΉ˜ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. AOTλŠ” μƒμ„±λœ sourceκ°€ build helperλ₯Ό 직접 importν•˜λ―€λ‘œ, κΈ°μ‘΄ ν”„λ‘œμ νŠΈμ—μ„œ AOTλ₯Ό ν™œμ„±ν™”ν•  λ•Œλ§Œ κ³ μ • 버전을 API 개발 μ˜μ‘΄μ„±μ— μΆ”κ°€ν•©λ‹ˆλ‹€.

As-is와 To-be

μ•Œλ €μ§„ λ™μž‘ 차이

zod-compiler 1.23.6은 recordμ—μ„œ enumerable string key만 μˆœνšŒν•˜κ³ , 일뢀 containerλŠ” μž…λ ₯ referenceλ₯Ό μœ μ§€ν•˜λ©°, per-call parse option을 λ¬΄μ‹œν•©λ‹ˆλ‹€. Schema-level error와 z.config()λŠ” κ·ΈλŒ€λ‘œ μ μš©λ©λ‹ˆλ‹€. μžμ„Έν•œ μ°¨μ΄λŠ” zod-compiler의 Behavioral Differencesλ₯Ό μ°Έμ‘°ν•˜μ„Έμš”. Sonamu HTTP validatorκ°€ μ‚¬μš©ν•˜λŠ” λŒ€ν‘œ coercionκ³Ό 였λ₯˜ κ²½λ‘œλŠ” benchmark parityλ₯Ό ν†΅κ³Όν–ˆμ§€λ§Œ, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ container identityλ‚˜ symbol key에 μ˜μ‘΄ν•œλ‹€λ©΄ opt-in 전에 λ³„λ„λ‘œ 확인해야 ν•©λ‹ˆλ‹€. 되돌리렀면 validation.zodCompilerλ₯Ό μ œκ±°ν•˜κ±°λ‚˜ false둜 λ°”κΎΈκ³  API package의 zod-compiler 개발 μ˜μ‘΄μ„±μ„ μ œκ±°ν•œ λ‹€μŒ sync와 buildλ₯Ό λ‹€μ‹œ μ‹€ν–‰ν•©λ‹ˆλ‹€. Syncκ°€ μƒμ„±λœ AOT registryλ₯Ό μ‚­μ œν•˜λ©°, handler cache와 κΈ°μ‘΄ BadRequestException/ZodError 계약은 μœ μ§€λ©λ‹ˆλ‹€. μ‹€μΈ‘ 쑰건과 κ²°κ³ΌλŠ” μ €μž₯μ†Œμ˜ docs/benchmarks/zod-compiler-http-validation.mdλ₯Ό μ°Έμ‘°ν•˜μ„Έμš”. λ‹€μ‹œ μ‹€ν–‰ν•œ 5회 benchmarkμ—μ„œ eager JITλŠ” validator-only median p95λ₯Ό 58.7%, AOTλŠ” 58.0% μ€„μ˜€μ§€λ§Œ, Fastify inject κ³„μΈ΅μ—μ„œλŠ” λ‘˜ λ‹€ 10% 기쀀을 λ„˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ compiler modeλŠ” opt-in으둜 μœ μ§€ν•©λ‹ˆλ‹€.

Zodλž€?

νƒ€μž… μ•ˆμ „ μŠ€ν‚€λ§ˆ

TypeScript νƒ€μž… μžλ™ μΆ”λ‘  별도 νƒ€μž… μ •μ˜ λΆˆν•„μš”

λŸ°νƒ€μž„ 검증

μ‹€ν–‰ μ‹œ 데이터 검증 잘λͺ»λœ 데이터 차단

μƒμ„Έν•œ μ—λŸ¬

ν•„λ“œλ³„ μ—λŸ¬ λ©”μ‹œμ§€ 디버깅 용이

λ³€ν™˜ & κΈ°λ³Έκ°’

데이터 λ³€ν™˜ 및 κΈ°λ³Έκ°’ μœ μ—°ν•œ 처리

κΈ°λ³Έ μ‚¬μš©λ²•

Zod μŠ€ν‚€λ§ˆλŠ” Entityμ—μ„œ μžλ™ μƒμ„±λ˜μ§€λ§Œ, 직접 μ •μ˜ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

μŠ€ν‚€λ§ˆ μ •μ˜

데이터 검증

parse vs safeParse:
  • parse(): μ—λŸ¬λ₯Ό λ˜μ§‘λ‹ˆλ‹€. try-catch둜 처리
  • safeParse(): μ—λŸ¬λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. result.success둜 체크
API ν•Έλ“€λŸ¬μ—μ„œλŠ” parse()λ₯Ό μ‚¬μš©ν•˜μ—¬ μžλ™μœΌλ‘œ 400 μ—λŸ¬λ₯Ό λ°˜ν™˜ν•˜κ³ , UIμ—μ„œλŠ” safeParse()둜 μ•ˆμ „ν•˜κ²Œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

κΈ°λ³Έ νƒ€μž… 검증

Entity의 각 νƒ€μž…λ³„ Zod κ²€μ¦μž…λ‹ˆλ‹€.

λ¬Έμžμ—΄ 검증

숫자 검증

λ‚ μ§œ 검증

뢈린 검증

볡합 νƒ€μž… 검증

λ°°μ—΄

객체

Enum

Union (μ—¬λŸ¬ νƒ€μž… 쀑 ν•˜λ‚˜)

κ³ κΈ‰ 검증 νŒ¨ν„΄

쑰건뢀 검증

데이터 λ³€ν™˜

κΈ°λ³Έκ°’ μ„€μ •

μ‹€μ „ 검증 νŒ¨ν„΄

API νŒŒλΌλ―Έν„° 검증

λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 검증

Form 검증

μ—λŸ¬ 처리

ZodError ꡬ쑰

μ—λŸ¬ λ©”μ‹œμ§€ μ»€μŠ€ν„°λ§ˆμ΄μ§•

μ—λŸ¬ ν¬λ§·νŒ…

μ„±λŠ₯ μ΅œμ ν™”

μŠ€ν‚€λ§ˆ μž¬μ‚¬μš©

λΆ€λΆ„ 검증

λ‹€μŒ 단계

E2E Type Safety

μ—”λ“œνˆ¬μ—”λ“œ νƒ€μž… μ•ˆμ „μ„±

Entity Types

Entity νƒ€μž… λ³€ν™˜

Generated Types

생성 νƒ€μž… ν™œμš©

Model Testing

Zod 검증 ν…ŒμŠ€νŠΈν•˜κΈ°