Skip to content

Commit

Permalink
Post: Zod를 사용한 선언적 데이터 검증 글 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
yiyb0603 authored Feb 27, 2024
2 parents e4514e3 + 101898a commit 42f22b7
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 5 deletions.
10 changes: 5 additions & 5 deletions posts/Develop/msw-usage.mdx → posts/TypeScript/msw-usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: MSW를 사용하여 API Mocking 하기
description: 프론트엔드 측에서 백엔드 API를 Mocking하여 더 효율적으로 개발을 해봅시다.
createdAt: 2023-12-04
thumbnail: /images/posts/develop/msw-usage/thumbnail.png
thumbnail: /images/posts/typescript/msw-usage/thumbnail.png
---

안녕하세요! 오늘은 백엔드 API를 Mocking 해주는 라이브러리인 `MSW`란 무엇이며, 사용방법에 대해서 알아보도록 하겠습니다.
Expand All @@ -17,7 +17,7 @@ thumbnail: /images/posts/develop/msw-usage/thumbnail.png

하지만 이를 보완하기 위해서 서버의 API가 개발 완료될때까지 클라이언트단에서 **모의로 동작**할 수 있게끔 설정을 해두면 어떨까요? 마치 실제 API와 통신이 이루어지는것처럼 코드를 작성할 수 있고, 추후에는 코드를 최소한으로 건드리며 실제 API로 바꿔칠 수 있다면 프론트엔드 개발자들은 시간을 더 효율적으로 사용할 수 있습니다.

![Mocking Service Worker](/images/posts/develop/msw-usage/msw.png)
![Mocking Service Worker](/images/posts/typescript/msw-usage/msw.png)

> 공식문서 바로가기: https://mswjs.io
Expand Down Expand Up @@ -189,11 +189,11 @@ export default App;

과연 API의 응답값이 저희가 임의로 반환한 값으로 응답이 올까요?

![MSW Mocking 실행 결과](/images/posts/develop/msw-usage/msw-get-response.png)
![MSW Mocking 실행 결과](/images/posts/typescript/msw-usage/msw-get-response.png)

원래 JSONPlaceholder API를 호출했을때 임의의 100개 데이터를 전달해주는 반면, API Mocking을 설정해두니 저희가 임의로 반환한 데이터가 올바르게 응답되었네요! 동시에 네트워크 탭을 보시면 `200 OK`가 뜨면서 서비스 워커에서 반환되었음을 알 수 있습니다.

![서비스 워커 반환](/images/posts/develop/msw-usage/from-service-worker.png)
![서비스 워커 반환](/images/posts/typescript/msw-usage/from-service-worker.png)

### 2-3. POST Mocking

Expand Down Expand Up @@ -279,7 +279,7 @@ POST 요청에 대해서도 API Mocking이 성공했을까요?

네! JSONPlaceholder API로 요청하는 데이터를 Mocking 서버에서 가로챈 후, 응답을 성공적으로 받을 수 있었습니다.

![POST API Mocking](/images/posts/develop/msw-usage/msw-post-response.png)
![POST API Mocking](/images/posts/typescript/msw-usage/msw-post-response.png)

API Mocking이 적용되는 과정을 아래처럼 요약할 수 있습니다.

Expand Down
265 changes: 265 additions & 0 deletions posts/TypeScript/zod-usage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
---
title: zod를 사용하여 선언적으로 데이터 검증하기
description: 선언적 데이터 검증 라이브러리 zod를 사용해봅시다.
createdAt: 2024-02-27
thumbnail: /images/posts/typescript/zod-usage/thumbnail.png
---

안녕하세요! 오늘은 **선언형 데이터 검증 라이브러리**`zod`란 무엇이며, 어떻게 사용하는지를 알아보겠습니다.

## 1. 기존의 데이터 검증 🤔

여러분이 진행하는 프로젝트에서 사용자로부터 **많은 입력값(회원가입, 글 작성 등등)**을 받는경우, 해당 입력값에 대해서 `검증`하는 절차가 작성되는 경우가 많습니다.

예를들어, 아래의 규칙을 따르는 데이터가 있다고 가정해봅시다.

```typescript
/*
email: 필수 입력, 이메일 정규식 맞춰야함
name: 필수 입력
password: 필수 입력, 비밀번호 정규식 맞춰야함
interestCategories: 2개 이상, 5개 이하로 선택해야함
*/

interface SignUpDto {
email: string;
name: string;
password: string;
interestCategories: number[];
}
```

위의 데이터를 검증시, 선언형 데이터 검증 라이브러리를 사용하지 않는경우에는 아래처럼 코드를 작성할 수 있습니다.

```typescript
interface ValidateResult {
succeed: boolean;
message: string;
}

const validateSignUpDto = (signUpDto: SignUpDto): ValidateResult => {
const { email, name, password, checkPassword, interestCategories } = signUpDto;

if (email.trim().length <= 0) {
return {
succeed: false,
message: '이메일을 입력해주세요.',
};
} else if (이메일 정규식에 안맞다면) {
return {
succeed: false,
message: '이메일 정규식에 맞게 입력해주세요.'
};
} else if (name.trim().length <= 0) {
return {
succeed: false,
message: '이름을 입력해주세요.',
};
} else if (password.trim().length <= 0) {
return {
succeed: false,
message: '비밀번호를 입력해주세요.',
};
} else if (비밀번호 정규식에 안맞다면) {
return {
succeed: false,
message: '비밀번호 정규식에 맞게 입력해주세요.',
};
} else if (interestCategories.length <= 2) {
return {
succeed: false,
message: '관심분야를 2개 이상 선택해주세요.',
};
} else if (interestCategories.length > 5) {
return {
succeed: false,
message: '관심분야는 5개 이하로 선택가능합니다.',
};
}

return {
succeed: true,
message: '성공',
};
};
```

위처럼 if문을 사용한 검증 함수를 만들고, `React`를 예시로 했을때 **컴포넌트나 커스텀 훅 등에서 함수를 불러와서 데이터를 검증**할 수 있습니다. 기능상으로는 문제가 없습니다.

<br />

그러나 위의 회원가입 기능에서 필요한 데이터가 추가되고, 그에따른 검증식도 늘어나면 어떻게 될까요? 검증 함수는 **점점 코드량이 증가하여 가독성이 매우 떨어지게 됩니다.** 이는 `유지보수`를 어렵게 만들 수 있는 코드가 되는것이죠.

이전까지 저도 저렇게 적었을때는 검증에 대한 코드를 작성하는것이 정말 귀찮았던 것 같습니다. 그래서 검증 코드를 잘 작성할 수 있는 방법을 찾아보다가, `zod` 라이브러리를 알게 되었습니다.

## 2. zod 검증 라이브러리 🔨

위처럼 모든 검증 과정을 작성한 코드(`명령형`)의 문제점을 해결하기 위해서 **간결하게 선언적으로 작성** 가능한 `zod` 라이브러리가 등장했습니다.

![zod 검증 라이브러리](/images/posts/typescript/zod-usage/zod.png)

> zod 라이브러리 공식 문서 [바로가기](https://zod.dev)
`zod` 라이브러리의 대표적인 장점을 몇가지 뽑아보자면

1. 선언적으로 데이터 검증 (코드 간결)
2. 타입스크립트 지원
3. 스키마 -> 타입 변환 지원 (중복 코드 최소화)

위의 장점들을 뽑을 수 있습니다. 그렇다면 `zod`를 코드에서 어떻게 작성할 수 있는지 알아봅시다.

> 오늘 소개드릴 `zod` 외에도 [yup](https://github.com/jquense/yup), [joi](https://joi.dev) 등의 검증 라이브러리도 훌륭하다고 생각하기에, 한번쯤 보시는걸 추천합니다. 😃
## 3. 사용방법 🔍

가장 먼저 npm, yarn 등의 패키지 매니저로 `zod`를 설치해줍니다.

```shell
npm install zod
```

또는

```shell
yarn add zod
```

기본적으로 `zod` 패키지에서 `z` 변수를 `import`하여 기능을 사용할 수 있습니다.

예를들어, 데이터의 타입이 string일때는 `z.string()`, number일때는 `z.number()` 등으로 작성할 수 있습니다.

```typescript
import { z } from 'zod';

const stringSchema = z.string();

const numberSchema = z.number();
```

### 3-1. 데이터 검증

`zod`는 선언적 데이터 검증이 주 특징입니다. 그래서 데이터 검증은 핵심기능으로도 볼 수 있습니다.

특정한 구조의 데이터를 검증하려면 `zod``스키마(Schema)`를 선언해야합니다. 스키마에서는 **필드별 데이터 타입, 규칙을 선언적으로 정의하여 구성**합니다. zod에서 제공하는 규칙용 메소드들은 다양한데요. 이번 글에서는 대표적으로 많이 사용되는 메소드들만 알려드리겠습니다.

<br />

이번 글에서 설명하지 않은 검증 메소드들에 대해서는 [zod 공식문서](https://zod.dev)에 설명이 매우 잘되어있으니 보시는걸 추천합니다.

<br />

위에서 예시로 설명드린 회원가입 예제를 `zod`로 변환하여 작성해보겠습니다. 코드에 대한 설명은 주석으로 적어두었습니다.

> zod는 함수형 프로그래밍 형태로 사용되는점을 미리 알아두시면 좋습니다.
```typescript
import { z } from 'zod'; // zod 패키지로부터 import

// 스키마 선언
// 회원가입과 같은 정보는 일반적으로 객체형태로 관리하기에, 객체임을 나타내는 z.object()로 감싸줍니다.
export const signUpSchema = z.object({
// 문자열 형태로 필수(1글자 이상), 올바른 이메일 형식
email: z
.string()
.trim()
.min(1, '이메일을 입력해주세요.')
.email('올바른 이메일을 입력해주세요.'),

// 문자열 형태로 필수 (1글자 이상)
name: z.string().trim().min(1, '이름을 입력해주세요.'),

// 문자열 형태로 필수(1글자 이상), 8자 이상의 알파벳으로 구성
password: z
.string()
.trim()
.min(1, '비밀번호를 입력해주세요.')
.regex(/b[a-zA-Z]{8,}/b, '8자 이상의 알파벳으로 구성되어야 합니다.'),

// 숫자 배열 형태로 필수, 배열 길이가 2이상, 5이하로 이루어져야함
interestCategories: z
.array(z.number())
.min(2, '2개 이상의 카테고리를 선택해주세요.')
.max(5, '5개 이하로 카테고리를 선택해주세요.'),
});
```

`zod`를 사용하면 데이터에 대한 검증 코드를 위처럼 간결하게 작성할 수 있습니다. 이전에 if문을 사용한 검증 코드와 비교했을때 정말 간결함을 알 수 있습니다.

위 코드에서 `min`, `max`, `email`과 같은 검증 메소드를 사용했음을 알 수 있는데요. 숫자 인자는 **만족하는 데이터 길이**이고, 문자열 인자는 **데이터를 만족하지 않을때 설정할** `오류 메세지`입니다.

<br />

이제 위의 스키마를 사용하여 데이터를 검증할 수 있는데요. 검증을 하는 방법은 대표적으로 `parse` 또는 `safeParse` 메소드를 사용하여 검증할 수 있습니다.

> `parse`: 검증 오류시, throw Error (try / catch 처리 필요)
> `safeParse`: 검증 오류시 오류의 정보를 담는 객체 반환
해당 메소드에 넘긴 데이터가 검증식에 맞지 않을경우, 실패합니다.

```typescript
try {
signUpSchema.parse({
email: 'asdf@gmail.com',
name: '권용빈',
password: 'asdfasdf',
interestCategories: [2], // 카테고리를 한개만 전달했기에, catch문으로 넘어간다. (오류)
});
} catch (error) {
// ZodError
}

// 올바른 형태의 데이터 전달, 성공
const parsed = signUpSchema.safeParse({
email: 'asdf@gmail.com',
name: '권용빈',
password: 'asdfasdf',
interestCategories: [2, 3, 4],
});

console.log(parsed.success); // true

// 올바르지 않은 형태의 데이터 전달, 실패
const parsed2 = signUpSchema.safeParse({
email: 'asdf', // 올바르지 않은 이메일 형식
name: '권용빈',
password: 'asdfasdf',
interestCategories: [2, 3, 4],
});

if (!parsed.success) {
console.log(parsed.error.errors[0].message); // 가장 첫번째 오류의 메세지 출력
}
```

> 🙋‍♂️ `safeParse` 메소드의 `success` 필드가 false로 추론될때만 `error` 필드에 접근이 가능합니다.
### 3-2. 스키마 -> 타입 변환

이번에는 `zod`로 선언한 스키마를 **타입스크립트의 타입으로 변환**하는 방법을 알아보겠습니다. 검증 스키마를 선언한 정보를 타입으로 변환이 가능하다면, 필드 정보를 중복으로 적을일이 없기때문에 개발자 입장에서 더 편합니다.

<br />

타입으로 변환하는 방법은 `z.infer` 타입을 사용하여 변환할 수 있습니다.

```typescript
import { z } from 'zod';

export type SignUpDto = z.infer<typeof signUpSchema>;

/*
email: string;
name: string;
password: string;
interestCategories: number[];
*/
```

## 4. 마치며 📌

오늘은 `zod` 라이브러리란 무엇이며, 어떻게 사용할 수 있는지를 간단하게 알아보았습니다.

저는 `zod`를 도입해보면서 코드를 더 간결하게 줄일 수 있어서 매우 좋았었는데요. 데이터 검증코드에 대해 고민이 있으시다면 한번 사용해보시는것을 추천합니다.

<br />

이상으로 글을 마치겠습니다. 읽어주셔서 감사합니다!
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/posts/typescript/zod-usage/zod.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 42f22b7

Please sign in to comment.