Zod를 활용한 유효성 검증-2

Odyssey·2025년 2월 14일
0

Next.js_study

목록 보기
32/58
post-thumbnail

2025.2.14 금요일의 공부기록

Zod는 문자열 검증뿐만 아니라 정규 표현식, 변환(transform), 공백 제거(trim), 소문자 변환(toLowerCase) 등의 다양한 기능을 제공한다.
이 기능들을 활용하면 보다 정밀한 데이터 검증 및 변환이 가능하다.

📌 공식 문서 참고:


정규 표현식을 활용한 검증 (.regex())

📌 예제 1: 비밀번호 강도 검사

import { z } from "zod";

// **비밀번호 정규표현식 (소문자, 대문자, 숫자, 특수문자 포함)**
const passwordRegex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?!@$%^&*-]).+$/);

const passwordSchema = z.string()
  .min(8, { message: "비밀번호는 최소 8자 이상이어야 합니다." })
  .regex(passwordRegex, { message: "비밀번호는 대문자, 소문자, 숫자, 특수문자를 포함해야 합니다." });

console.log(passwordSchema.safeParse("Abc123!@#"));  // ✅ 통과
console.log(passwordSchema.safeParse("abc123"));     // ❌ 실패 (대문자, 특수문자 없음)
console.log(passwordSchema.safeParse("ABC123!@#"));  // ❌ 실패 (소문자 없음)

📌 설명:

  • .regex(passwordRegex, { message }) → 정규 표현식을 사용하여 대소문자, 숫자, 특수문자 포함 여부를 검증.
  • .min(8, { message }) → 비밀번호 최소 길이 검증.

📌 예제 2: 전화번호 검증 (한국형식)

const phoneSchema = z.string().regex(/^010-\d{4}-\d{4}$/, {
  message: "올바른 전화번호 형식이 아닙니다. (예: 010-1234-5678)",
});

console.log(phoneSchema.safeParse("010-1234-5678")); // ✅ 통과
console.log(phoneSchema.safeParse("123-456-7890")); // ❌ 실패
console.log(phoneSchema.safeParse("01012345678"));  // ❌ 실패

📌 설명:

  • .regex(/^010-\d{4}-\d{4}$/)"010-1234-5678" 형식인지 검증.

문자열 변환 기능 (.toLowerCase(), .trim())

📌 예제 1: 이메일 소문자로 변환

const emailSchema = z.string().email().toLowerCase();

console.log(emailSchema.parse("User@Example.com")); // ✅ "user@example.com"
console.log(emailSchema.parse("TEST@GMAIL.COM"));   // ✅ "test@gmail.com"

📌 설명:

  • .toLowerCase()모든 문자를 소문자로 변환.

📌 예제 2: 사용자 입력 공백 제거 (.trim())

const usernameSchema = z.string().trim();

console.log(usernameSchema.parse("  user123  ")); // ✅ "user123"
console.log(usernameSchema.parse("   hello   ")); // ✅ "hello"

📌 설명:

  • .trim()앞뒤 공백을 자동으로 제거.

데이터 변환 (.transform())

Zod의 .transform()을 활용하면 데이터를 변환하여 원하는 형식으로 저장할 수 있다.

📌 예제 1: 문자열 길이를 숫자로 변환

const stringToNumber = z.string().transform((val) => val.length);

console.log(stringToNumber.parse("Hello")); // ✅ 5
console.log(stringToNumber.parse("Zod!"));  // ✅ 4

📌 설명:

  • .transform((val) => val.length) → 문자열의 길이를 반환하는 스키마.

📌 예제 2: 사용자 이름 앞뒤에 이모지 추가

const usernameSchema = z.string().transform((username) => `🔥 ${username} 🔥`);

console.log(usernameSchema.parse("John")); // ✅ "🔥 John 🔥"
console.log(usernameSchema.parse("Alice")); // ✅ "🔥 Alice 🔥"

📌 설명:

  • .transform((username) => 🔥 ${username} 🔥)이모지를 추가한 변형된 값을 반환.

📌 예제 3: 숫자로 변환 후 검증

const numberSchema = z.string()
  .transform((val) => Number(val))
  .refine((num) => num > 0, { message: "숫자는 0보다 커야 합니다." });

console.log(numberSchema.safeParse("10"));  // ✅ 10
console.log(numberSchema.safeParse("-5"));  // ❌ 실패 (음수는 허용되지 않음)
console.log(numberSchema.safeParse("abc")); // ❌ 실패 (숫자가 아님)

📌 설명:

  • .transform((val) => Number(val)) → 문자열을 숫자로 변환.
  • .refine((num) => num > 0, { message })0보다 큰 숫자인지 검증.

Zod를 활용한 Next.js 데이터 검증 예시 실습 코드

📌 createAccount 서버 액션 (회원가입 검증)

"use server";

import { z } from "zod";

function checkUsername(username: string) {
  return !username.includes("admin");
}

const passwordRegex = new RegExp(
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#?!@$%^&*-]).+$/
);

const checkPasswords = ({
  password,
  confirm_password,
}: {
  password: string;
  confirm_password: string;
}) => password === confirm_password;

const formSchema = z
  .object({
    username: z
      .string({
        invalid_type_error: "Username must be a string",
        required_error: "Username is required",
      })
      .min(3, "Way too short!!")
      .max(10, " Way too long!!")
      .toLowerCase()
      .trim()
      .transform((username) => `${username}🇰🇷`)
      .refine(checkUsername, "Username cannot contain 'admin'"),
    email: z.string().email(),
    password: z
      .string()
      .min(10)
      .regex(
        passwordRegex,
        "Password too weak, must contain at least one uppercase letter, one lowercase letter, and one special character"
      ),
    confirm_password: z.string().min(10),
  }) //아래의 refine은 form 전체에 대한 refine임을 주의 confirm_password에 붙은 게 아님
  .refine(checkPasswords, {
    message: "Passwords do not match",
    path: ["confirm_password"],
  });

export async function createAccount(prevState: any, formData: FormData) {
  const data = {
    username: formData.get("username"),
    email: formData.get("email"),
    password: formData.get("password"),
    confirm_password: formData.get("confirm_password"),
  };
  const result = formSchema.safeParse(data);

  if (!result.success) {
    return result.error.flatten();
  }
}

📌 설명:

  • trim()공백 제거.
  • toLowerCase()이메일을 소문자로 변환.
  • .regex()비밀번호 복잡도 검사.
  • .refine()비밀번호 & 비밀번호 확인 일치 검증.

Zod 유효성 검사 기능 정리

✅ 기능🛠 설명
정규 표현식 검증.regex(/정규식/, { message })
소문자로 변환.toLowerCase()
공백 제거.trim()
데이터 변환.transform((val) => 변환 값)
비밀번호 강도 검증.regex(passwordRegex, { message })
숫자로 변환 후 검증.transform((val) => Number(val)).refine((num) => num > 0, { message })

📌 더 자세한 내용은 Zod 공식 문서를 참고하자! 🚀

0개의 댓글