본문 바로가기
Tech Notes

요즘은 schema로 client + server 둘 다 validation 하는 게 거의 표준인가봐!

by miracle-tech 2025. 7. 7.
728x90
반응형

 

옛날 사람이라 입력값은 화면에서(frontend) 하고, 넘어온 값으로 처리(backend)를 하는 게 보통이라고 생각했는데,

지금 프로젝트 똑같은 validation 을 양쪽에서 다 하고 있었다.

'왜그러지?' 하고 넘어갔었는데

개인 프로젝트를 하면서 AI Tool 이 만들어준 로직을 보다가 궁금증이 생겨 알아보니 ChatGPT 가 다음과 같은 대답을 해줬다.

 

🔑 왜?

1️⃣ 중복된 로직을 줄임

예전에는:

  • 클라이언트: JS에서 if (!email.includes('@')) 이런 거 하고,
  • 서버: 다시 express나 django에서 if (!email) 또 함.

👉 이렇게 두 번, 세 번 같은 로직을 중복으로 씀.


2️⃣ 동일한 스키마로 유지보수 편함

Zod, Yup, Joi 같은 schema validator를 쓰면:

  • 같은 스키마를 클라이언트와 서버에서 공유 가능!
  • 예) Next.js, Remix, tRPC, Nuxt 등 풀스택 프레임워크에서 엄청 잘 씀.

3️⃣ 서버 쪽 검증은 필수

  • 클라이언트 검증만 하면 → 사용자가 devtools로 자바스크립트 꺼버리면 끝.
  • 그래서 서버는 무조건 최종 검증자 역할.
  • 즉, 클라에서 잡고 → 서버에서 한 번 더 잡는 구조.

4️⃣ tRPC + Zod = 요즘 대세

  • 요즘 tRPC, Remix, Next.js app router 쓰면,
    Zod 같은 schema를 한 파일에 두고
    → 클라이언트와 서버가 같이 import 해서 씀.
  • 유지보수도 쉽고, 타입도 공유됨.
  • 예: z.infer<typeof mySchema> 쓰면 프론트 타입 자동.

✅ 예시 흐름

1️⃣ schema.ts

export const registerSchema = z.object({
  email: z.string().email(),
  password: z.string().min(6),
});

2️⃣ Client

useForm({
  resolver: zodResolver(registerSchema)
});

3️⃣ Server

const parsed = registerSchema.parse(req.body);

🔒 왜 이렇게 해야 안전하냐?

  • 클라이언트만 믿으면 안 됨 → 해커는 API에 직접 POST 날려버림.
  • 서버가 마지막 방패막.

✅ 결론: 요즘 개발의 정석

한 스키마로 둘 다 체크 = DRY + 안전 + 유지보수 편함

 

🤨  : 현재 프로젝트는 안타깝게도 동일한 validation 에 대해 schema 를 공유해서 쓰고 있지 않다.

따라서, 동기화가 안되서 문제가 종종 발생한다. 

'왜 똑같은 걸 두번 하냐?' 라고만 생각했는데 잘 적용했으면 그럴 이유가 없었구나....

728x90