목차
1. zod란?
2. 왜 zod로 타입검사를 할까?
3. 타입들과 메서드
4. 사용법
1. zod란?
- Typescript의 스키마 선언 및 데이터 검증을 위한 유효성 검증 라이브러리
자바스크립트와 같은 동적 프로그래밍 언어를 사용하여 프로그래밍을 할 때 중요하게 다루어야할 문제 중 하나가 데이터의 타입과 유효성을 검증하는 것이다. 자바스크립트는 해당 타입의 문제를 해결하기 위해 Typescript를 사용하는데 이것만으로는 부족한 부분이 있다. 왜 사용하는지, 어떻게 사용하는지 알아보고 필요할 때 적절히 사용해보도록 하자.
2. 왜 zod로 타입검사를 할까?
typescript에서는 type을 통해 생성한 DTO, interface 등 검증을 위한 방법이 있다. 그럼에도 불구하고 왜 zod를 사용하는 것일까?
typescript부터 type과 interface까지 파일 변환 단계에서 검증이 가능하지만 아쉽게도 런타임 단계에서는 검증하지 못한다. 그래서 js파일로 변환한 후 데이터를 전달할 때 타입이 맞지 않아도 에러가 발생하지 않아 생각과는 다른 결과가 나올 수 있다.
하지만 zod의 경우 파일 변환 단계부터 런타임단계까지 데이터의 타입을 검증하는 것이 가능하다.
3. 타입들과 메서드
zod는 typescript에서 지정하는 타입을 별도의 타입 지정 메서드를 통해 타입을 지정하고 검증한다.
1) 타입
string
▶ 문자열 타입 스키마를 생성하는 메서드
const strSchema = z.string();
//최소 길이지정
const strSchema = z.string().min(최소길이);
//최대 길이지정
const strSchema = z.string().max(최소길이);
number
▶ 숫자 타입의 스키마를 생성하는 메서드
const numberSchema = z.number();
// 최소값지정
const numberSchema = z.number().min(최솟값);
// 최대값지정
const numberSchema = z.number().max(최댓값);
boolean
▶ 데이터를 true/false의 boolean 타입으로 지정
const value = z.boolean()
array
▶ 데이터를 배열 타입으로 지정
▶ 어떤 타입의 배열인지 인자값을 통해 지정해주어야 한다.
const arr = z.array(타입)
//ex)
// 여러 문자열 데이터가 있는 배열
const arr = z.array(z.string());
object
▶ 객체 타입으로 지정
const obj = z.object({
속성1:값1,
속성2:값2
})
Nullable
▶ null일 수 있는 타입을 지정
▶ 다른 타입과 체이닝으로 사용가능
const schema = z.object({
name: z.string().nullable(),
})
2) 메서드
parse
▶ 입력데이터의 타입을 스키마와 비교하여 검증하는 메서드로 스키마와 맞지 않으면 에러를 발생시킨다.
스키마.parse('데이터');
// ex)
const str = z.string();
z.parse("test") => test
z.parse(123) => Error
safeParse
▶ parse메서드와 같이 스키마와 비교 검증을 하지만 스키마와 맞지 않아도 에러를 발생시키지 않고 검증 결과를 객체로 반환한다.
스키마.safeParse('데이터');
// ex)
const str = z.string();
z.safeParse("test") => {success:true,data:"test"}
z.safeParse(123) => {success:false,error:ZodError}
transform
▶ 데이터 검증 후 성공하면 타입을 변환한다.
const str = z.string().transform((val) => val.toUpperCase());
const result = str.safeParse("test") => { success: true, data: 'TEST' }
4. 사용법
1) 모듈 추가
zod는 외부 라이브러리기 때문에 다운을 받아야 사용이 가능하다.
npm install zod
2) 타입 생성
// DTO.ts
import {z} from 'zod';
const schema = z.object({
name:z.string(),
age:z.number()
})
3) 파이프 생성
굳이 파이프를 통해 데이터를 검증할 필요는 없지만 controller의 메서드를 실행하기 전 작업에 필요한 데이터를 검증하는 것이 좋고 다른 경로로 요청할 때도 필요할 수 있기 때문에 파이프를 생성하여 사용하도록 한다. 만들어둔 zod 스키마를 전달받아 검증받을 것이기 때문에 생성자를 통해 속성을 정의해둔다.
// pipe.ts
import { ArgumentMetadata, PipeTransform } from "@nestjs/common";
import { z } from 'zod';
export class TestPipe implements PipeTransform {
schema: z.Schema;
constructor(schema: z.Schema) {
this.schema = schema
}
transform(value: any, metadata: ArgumentMetadata) {
try {
const result = this.schema.safeParse(value);
if (result.success)
return value
} catch (error) {
console.log(error);
}
}
}
4) 데이터 검증
controller에서 메서드가 실행하기 전 만들어둔 파이프를 실행하도록 하고 검증에 필요한 zod스키마를 지정하도록한다. 파이프를 통해 body에 담긴 데이터의 타입검증이 진행되며 타입이 맞다면 데이터가 그대로 반환되고 아니면 body에는 데이터가 담기지 않게 된다.
// 프론트에서 객체 타입의 데이터 전송
// {name:'홍길동',age:10}
@Controller('test')
class Controller {
@Post()
create(@Body(new TestPipe(schema)) data: typeof schema) {
console.log(data);
return null;
}
}
5) 결과 확인
참고자료
GitHub - colinhacks/zod: TypeScript-first schema validation with static type inference
TypeScript-first schema validation with static type inference - colinhacks/zod
github.com