유효성 체크
X2BEE 솔루션에서 Zod 라이브러리를 사용해 데이터 유효성을 검증합니다. 본 가이드는 스키마 정의, 필드별 유효성 검증, 전체 데이터 검증, 데이터 가공 및 타입 추론을 효율적으로 구현하는 방법을 설명합니다.
1
Zod 스키마 정의 방법
Zod는 TypeScript를 우선으로 하는 스키마 선언 및 유효성 검증 라이브러리이며, 중복된 유형 선언을 제거하기 위해 사용됩니다. Zod를 통해 유효성 검사를 하고 TypeScript 유형을 추론할 수 있습니다.
import { z } from 'zod'
/** 기본적인 zod 객체 선언은 내부에 object 함수를 이용하여 객체를 생성하고 반환해줄 수 있습니다.
Argument로 객체를 던져주면 상수 형태의 zod schema를 사용할 수 있습니다.
Argument로 전달하는 객체의 경우 각 필드를 정의하고 타입을 zod의 타입으로 정의해줘야 합니다.
**/
const zodExampleSchema = z.object({
name: z.string(),
userId: z.string(),
password: z.string(),
phone: z.number()
})2
각 필드별 유효성 체크 방법
Zod만으로는 일부 자유도 높은 검증에 제한이 있으므로, 각 항목에 대해 refine를 사용한 필드별 커스텀 검증을 적용할 수 있습니다. 아래는 빈 값 체크 등 기본적인 검증 예시입니다.
import { z } from 'zod'
/** min, max 등 다양한 기본 검증 방식들이 존재하지만,
자유도 있는 검증을 위해 zod의 refine를 이용할 수 있습니다.
refine의 첫번째 인자는 검증 통과 여부(boolean)를 반환하는 함수,
두번째 인자는 메시지 등의 옵션입니다.
**/
const zodExampleSchema = z.object({
name: z.string().refine(
(data) => !!data, // data는 name 필드의 값을 의미 (boolean 반환)
{
message: "이름을 입력해주세요."
}
),
userId: z.string(),
password: z.string(),
phone: z.number()
})3
전체 필드를 대상으로 한 유효성 체크 방법
필드 간 참조가 필요한 검증(예: 비밀번호와 비밀번호 확인 일치 여부)은 개별 필드의 refine로는 어려우므로, object 레벨에서 superRefine를 사용합니다. superRefine는 전체 데이터 객체와 컨텍스트를 받아 복합 검증을 수행할 수 있습니다.
import { z } from 'zod'
/** superRefine는 z.object에 적용되는 함수로,
첫번째 인자는 전체 필드 데이터를 가진 객체,
두번째 인자는 zod의 context(ctx) 입니다.
**/
const zodExampleSchema = z.object({
userId: z.string(),
password: z.string(),
rePassword: z.string()
}).superRefine((data, ctx) => {
if (data.password !== data.rePassword) {
ctx.addIssue({
message: "비밀번호가 일치하지 않습니다.",
code: z.ZodIssueCode.custom,
path: ['password']
})
return false
}
return true
})4
최종 스키마 데이터 가공 방법
검증 후 반환되는 데이터를 변환하거나 불필요한 필드를 제거하는 등 스키마 레벨에서 데이터를 가공하려면 transform을 사용합니다. transform은 검증이 통과된 후 최종값으로 변환된 객체를 반환합니다. 필요하다면 transform 전에 데이터를 가공하고 superRefine로 검증할 수도 있습니다.
import { z } from 'zod'
/** 아래 예시는 아이디 비어있음 체크, 비밀번호 확인 검사 후
transform로 최종 반환값을 가공하는 예시입니다.
**/
const zodExampleSchema = z.object({
userId: z.string().refine(
(data) => !!data,
{ message: "아이디를 입력해주세요." }
),
password: z.string(),
rePassword: z.string()
}).superRefine((data, ctx) => {
if (data.password !== data.rePassword) {
ctx.addIssue({
message: "비밀번호가 일치하지 않습니다.",
code: z.ZodIssueCode.custom,
path: ['password']
})
return false
}
return true
}).transform((data) => {
return {
userId: data.userId,
password: data.password
}
})마지막 업데이트