본문 바로가기
카테고리 없음

zod로 타입 검사하기

by 개발자doc 2024. 7. 25.
목차
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) 결과 확인 

 

참고자료

https://zod.dev

 

GitHub - colinhacks/zod: TypeScript-first schema validation with static type inference

TypeScript-first schema validation with static type inference - colinhacks/zod

github.com