Language/Typescript

Zod 사용법: 타입스크립트 유효성 검사를 쉽게 하는 방법 (3)

JohnnyDeveloper 2024. 10. 2. 18:18

Zod로 커스텀 유효성 검사 만들기

Zod의 기본적인 유효성 검사 기능 외에도 특정 조건에 맞는 데이터를 검증해야 할 때가 있습니다. 예를 들어, 비밀번호 복잡성이나 커스텀 비즈니스 로직에 맞는 유효성 검사가 필요할 수 있습니다. Zod는 이러한 요구를 만족시키기 위해 refine()와 같은 메서드를 제공하여 커스텀 유효성 검사를 손쉽게 구현할 수 있게 합니다.

4.1 기본 커스텀 유효성 검사

refine() 메서드를 사용하면 간단한 조건을 추가하여 커스텀 유효성 검사를 수행할 수 있습니다. 예를 들어, 비밀번호가 8자 이상인지 검증하려면 다음과 같이 할 수 있습니다:

const passwordSchema = z.string().refine((val) => val.length >= 8, {
  message: "비밀번호는 최소 8자 이상이어야 합니다.",
});

try {
  passwordSchema.parse("password123");  // 성공
  passwordSchema.parse("short");        // 오류: 비밀번호는 최소 8자 이상이어야 합니다.
} catch (e) {
  console.error(e.errors);
}
  • refine() 메서드를 사용하여 비밀번호의 길이가 8자 이상인지 검사합니다.
  • 조건이 맞지 않을 경우 message 옵션을 통해 명확한 오류 메시지를 표시합니다.

4.1.1 조건부 유효성 검사

refine()를 사용하면 단순한 길이 검사 외에도 조건에 따라 다양한 유효성 검증 로직을 적용할 수 있습니다. 예를 들어, 특정 필드의 값이 존재할 경우 다른 필드가 반드시 포함되어야 하는 경우를 생각해봅시다.

const registrationSchema = z.object({
  email: z.string().optional(),
  phoneNumber: z.string().optional(),
}).refine((data) => data.email || data.phoneNumber, {
  message: "이메일이나 전화번호 중 하나는 반드시 입력해야 합니다.",
});

try {
  registrationSchema.parse({ email: "", phoneNumber: "" }); // 오류 발생
} catch (e) {
  console.error(e.errors);
}
  • 이메일과 전화번호 중 하나라도 입력되지 않으면 오류가 발생합니다.
  • 이런 방식으로 조건부 유효성 검사를 설정하여 데이터의 일관성을 유지할 수 있습니다.

4.2 여러 개의 커스텀 검증 추가하기

Zod는 여러 개의 refine()를 체인처럼 연결하여 다양한 조건을 검증할 수 있도록 합니다. 예를 들어, 사용자의 username에 대해 길이와 특수문자 포함 여부를 동시에 검증해봅시다.

const usernameSchema = z.string()
  .min(5, { message: "사용자 이름은 최소 5자 이상이어야 합니다." })
  .refine((val) => /^[a-zA-Z0-9_]+$/.test(val), {
    message: "사용자 이름은 알파벳, 숫자, 밑줄(_)만 포함할 수 있습니다.",
  });

try {
  usernameSchema.parse("user_123"); // 성공
  usernameSchema.parse("u$er");     // 오류 발생
} catch (e) {
  console.error(e.errors);
}
  • min(5)는 최소 길이를 정의하고, refine()는 정규식을 사용해 특수 문자의 사용 여부를 확인합니다.
  • 이를 통해 데이터에 대한 더 세밀한 유효성 검사가 가능해집니다.

4.3 커스텀 오류 처리 및 메시지 설정

Zod의 refine()는 커스텀 오류 메시지를 제공하여 사용자에게 명확한 피드백을 주도록 도와줍니다. 오류 메시지는 사용자 친화적일수록, 그리고 문제의 원인을 명확히 설명할수록 좋습니다.

4.3.1 사용자 맞춤형 오류 메시지

예를 들어, 등록 양식에서 password와 confirmPassword가 일치하는지 검사하는 경우를 살펴보겠습니다:

const passwordMatchSchema = z.object({
  password: z.string(),
  confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
  message: "비밀번호와 비밀번호 확인이 일치해야 합니다.",
});

try {
  passwordMatchSchema.parse({
    password: "securePassword123",
    confirmPassword: "securePassword124",
  }); // 오류: 비밀번호와 비밀번호 확인이 일치해야 합니다.
} catch (e) {
  console.error(e.errors);
}
  • refine()를 사용하여 두 필드가 동일한지 검증하며, 일치하지 않을 경우 명확한 오류 메시지를 제공합니다.
  • 이를 통해 사용자에게 수정해야 할 부분을 정확히 알려줄 수 있습니다.