Zod의 refine과 superRefine
핵심 개념
두 메서드 모두 커스텀 유효성 검증을 추가하는 기능이지만, 복잡도와 제어 수준이 다릅니다.
refine - 간단한 커스텀 검증
언제 사용하나요?
- 단순한 조건 검증이 필요할 때
- 하나의 검증 규칙만 추가하면 될 때
특징
- 검증 함수가
boolean을 반환 true면 통과,false면 에러- 에러 메시지와 경로를 간단하게 지정 가능
예시 코드
const passwordSchema = z.string().refine((val) => val.length >= 8, {
message: '비밀번호는 8자 이상이어야 합니다',
})
const userSchema = z
.object({
password: z.string(),
confirmPassword: z.string(),
})
.refine((data) => data.password === data.confirmPassword, {
message: '비밀번호가 일치하지 않습니다',
path: ['confirmPassword'], // 에러가 표시될 필드
})
superRefine - 복잡한 커스텀 검증
언제 사용하나요?
- 여러 개의 에러를 동시에 발생시켜야 할 때
- 조건부로 다른 필드를 검증해야 할 때
- 더 세밀한 제어가 필요할 때
특징
ctx(context) 객체를 통해 에러를 직접 추가ctx.addIssue()로 여러 에러를 한 번에 발생 가능- 더 복잡한 검증 로직 구현 가능
예시 코드
const formSchema = z
.object({
email: z.string(),
password: z.string(),
confirmPassword: z.string(),
})
.superRefine((data, ctx) => {
// 여러 검증을 동시에 수행
if (data.password !== data.confirmPassword) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: '비밀번호가 일치하지 않습니다',
path: ['confirmPassword'],
})
}
if (data.password.length < 8) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: '비밀번호는 8자 이상이어야 합니다',
path: ['password'],
})
}
// 조건부 검증
if (data.email.includes('admin') && data.password.length < 12) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: '관리자 계정은 12자 이상의 비밀번호가 필요합니다',
path: ['password'],
})
}
})
선택 기준
| 상황 | 추천 메서드 |
|---|---|
| 단순한 true/false 검증 | refine |
| 하나의 에러만 발생 | refine |
| 여러 필드에 동시 에러 발생 | superRefine |
| 복잡한 조건부 검증 | superRefine |
| 에러 코드 커스터마이징 | superRefine |
실전 팁
- 체이닝 가능: 두 메서드 모두 여러 번 체이닝 가능
- 성능: 간단한 경우
refine이 더 가독성 좋음 - 에러 메시지: 사용자에게 명확한 피드백을 줄 수 있도록 구체적으로 작성
- path 지정: React Hook Form 등과 함께 사용할 때 정확한 필드에 에러 표시 가능
마치며
간단한 검증은 refine으로, 복잡한 검증은 superRefine으로 처리하면서 상황에 맞게 선택하여 사용하세요!