2025.2.9 일요일의 공부기록
Zod는 정적 타입 추론을 제공하는 TypeScript 스키마 검증 라이브러리로,
유효성 검사(Type Validation)와 데이터 변환(Data Parsing)을 쉽게 할 수 있도록 도와준다.
📌 공식 문서:
npm install zod
.parse()
사용하여 데이터 검증import { z } from "zod";
// 문자열 스키마 생성
const stringSchema = z.string();
console.log(stringSchema.parse("fish")); // ✅ 유효 → "fish"
console.log(stringSchema.parse(12)); // ❌ 오류 발생 (숫자는 허용되지 않음)
📌 설명:
.parse()
를 사용하면 데이터가 유효하면 그대로 반환하고, 유효하지 않다면 오류가 발생한다.createAccount
함수)"use server";
import { z } from "zod";
// **Zod 스키마 정의**
const usernameSchema = z.string().min(5).max(10);
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"),
};
// **유효성 검사**
usernameSchema.parse(data.username);
}
📌 설명:
usernameSchema
를 사용하여 username
이 최소 5자, 최대 10자인지 검사..parse()
를 사용하면 검증 실패 시 오류가 발생하여 코드 실행이 중단됨.const registerSchema = z.object({
username: z.string().min(5).max(10),
email: z.string().email(),
password: z.string().min(6),
confirm_password: z.string().min(6),
}).refine((data) => data.password === data.confirm_password, {
message: "비밀번호가 일치하지 않습니다.",
path: ["confirm_password"],
});
📌 설명:
.object()
를 사용하여 여러 필드를 동시에 검사..email()
→ 이메일 형식 검증..min(6)
→ 비밀번호 최소 6자 이상..refine()
을 사용하여 비밀번호 & 비밀번호 확인이 일치하는지 검사.createAccount
함수에서 검증 적용"use server";
import { z } from "zod";
const registerSchema = z.object({
username: z.string().min(5).max(10),
email: z.string().email(),
password: z.string().min(6),
confirm_password: z.string().min(6),
}).refine((data) => data.password === data.confirm_password, {
message: "비밀번호가 일치하지 않습니다.",
path: ["confirm_password"],
});
export async function createAccount(prevState: any, formData: FormData) {
const data = {
username: formData.get("username")?.toString(),
email: formData.get("email")?.toString(),
password: formData.get("password")?.toString(),
confirm_password: formData.get("confirm_password")?.toString(),
};
try {
registerSchema.parse(data);
return { success: true, message: "회원가입 성공!" };
} catch (error) {
return { success: false, message: error.errors[0].message };
}
}
📌 설명:
.parse()
를 try-catch로 감싸서 오류 발생 시 메시지 반환.error.errors[0].message
를 사용하여 첫 번째 검증 오류 메시지를 출력.useActionState
로 데이터 검증하기"use client";
import { useActionState } from "react";
import { createAccount } from "@/server-actions";
export default function RegisterForm() {
const [state, formAction, isPending] = useActionState(createAccount, { success: null, message: "" });
return (
<div className="flex flex-col gap-10 py-8 px-6">
<h1 className="text-2xl">회원가입</h1>
<form action={formAction} className="flex flex-col gap-3">
<input name="username" type="text" placeholder="Username" className="border p-2" required />
<input name="email" type="email" placeholder="Email" className="border p-2" required />
<input name="password" type="password" placeholder="Password" className="border p-2" required />
<input name="confirm_password" type="password" placeholder="Confirm Password" className="border p-2" required />
<button type="submit" disabled={isPending} className="bg-blue-500 text-white px-4 py-2 rounded-md">
{isPending ? "가입 중..." : "가입하기"}
</button>
</form>
{state.message && (
<p className={state.success ? "text-green-500" : "text-red-500"}>{state.message}</p>
)}
</div>
);
}
📌 설명:
useActionState()
를 사용하여 서버 액션(createAccount
)의 상태를 자동으로 관리.isPending
을 활용하여 폼 제출 중 버튼을 비활성화.state.message
를 출력하여 회원가입 성공/실패 메시지를 표시..safeParse()
: 오류 발생 없이 유효성 검사const result = registerSchema.safeParse({
username: "user",
email: "invalid-email",
password: "123456",
confirm_password: "123456",
});
if (!result.success) {
console.log(result.error.format());
}
📌 설명:
.parse()
는 유효하지 않으면 오류를 던지지만, .safeParse()
는 오류가 발생해도 실패 정보를 객체로 반환..strict()
: 예상치 못한 값이 포함된 경우 오류 발생const userSchema = z.object({
name: z.string(),
age: z.number(),
}).strict();
userSchema.parse({ name: "John", age: 25, extra: "unexpected" }); // ❌ 오류 발생
📌 설명:
.strict()
을 사용하면 정의되지 않은 값이 포함될 경우 오류 발생..transform()
: 데이터 변환const nameSchema = z.string().transform((val) => val.toUpperCase());
console.log(nameSchema.parse("john")); // "JOHN"
📌 설명:
.transform()
을 사용하여 데이터를 자동 변환 가능.✅ 기능 | 🛠 설명 |
---|---|
유효성 검사 | .parse() 또는 .safeParse() 사용 |
폼 데이터 검증 | useActionState() + Zod |
비밀번호 일치 검사 | .refine() 사용 |
자동 변환 | .transform() 사용 |