Zod와 객체지향 프로그래밍의 통합
Zod는 타입스크립트 중심의 데이터 스키마 검증 라이브러리로, 선언식 방식으로 데이터 구조와 검증 규칙을 정의할 수 있습니다. 이 가이드에서는 객체지향 프로그래밍 원칙과 Zod를 결합하여 유지보수성과 확장성을 극대화하는 검증 시스템을 설계하는 방법을 다룹니다.
Zod 기반 검증 패턴
Zod의 핵심은 Schema 클래스입니다. 다양한 검증기들은 이 기본 클래스를 상속하여 구현됩니다:
export abstract class Schema<Output = any, Input = Output, Def extends TypeDef = TypeDef> {
readonly _def: Def;
constructor(def: Def) {
this._def = def;
}
parse(data: unknown): Output {
// 검증 로직
}
}
검증 기반 클래스 설계
공통 검증 로직을 포함한 기본 클래스를 생성합니다:
class ValidationBase {
protected ruleSet: z.ZodSchema;
constructor(rules: z.ZodSchema) {
this.ruleSet = rules;
}
validate(input: unknown) {
const result = this.ruleSet.safeParse(input);
if (!result.success) {
throw new Error(`검증 실패: ${JSON.stringify(result.error)}`);
}
return result.data;
}
}
상속을 통한 기능 확장
특정 도메인에 맞춘 검증 로직을 추가합니다:
class UserValidator extends ValidationBase {
constructor() {
super(
z.object({
username: z.string().min(3, '아이디는 최소 3자여야 합니다'),
emailAddress: z.string().email('잘못된 이메일 형식'),
birthYear: z.number().positive('년도는 양수여야 합니다')
})
);
}
sanitize(input: unknown) {
const data = this.validate(input);
return { ...data, username: data.username.trim() };
}
}
복합 검증 시스템 구축
다중 검증 클래스를 조합하여 복잡한 구조를 처리합니다:
class AddressValidator extends ValidationBase {
constructor() {
super(
z.object({
street: z.string(),
city: z.string(),
postalCode: z.string().regex(/^[0-9]{5}$/, '올바른 우편번호가 아닙니다')
})
);
}
}
class ExtendedUserValidator extends UserValidator {
private addressValidator: AddressValidator;
constructor() {
super();
this.addressValidator = new AddressValidator();
}
validateWithAddress(input: unknown) {
const userData = super.validate(input);
if (userData.address) {
userData.address = this.addressValidator.validate(userData.address);
}
return userData;
}
}
설계 패턴 적용 가이드
- 단일 책임 원칙: 각 검증 클래스는 특정 데이터 유형만 담당
- 개방/폐쇄 원칙: 기존 코드 수정 없이 기능 확장 가능
- 의존성 주입: 관련 검증기들을 외부에서 주입
- 오류 처리 표준화: 공통 오류 처리 메커니즘 구현
Zod의 소스코드에서 Schema 클래스 구조를 분석하면 검증 시스템 설계에 대한 많은 통찰을 얻을 수 있습니다.