0Pricing
tRPC End-to-End Type Safe APIs · 강의

복잡한 Zod 스키마 정의

객체, 배열, 사용자 지정 검증 규칙을 위한 고급 Zod 스키마를 만드는 방법을 배웁니다.

복잡한 Zod 스키마 정의은(는) CoddyKit의 무료 tRPC End-to-End Type Safe APIs 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 tRPC End-to-End Type Safe APIs 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. tRPC End-to-End Type Safe APIs 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Beyond Basic Zod Types

Welcome back! In the previous lesson, we learned about Zod's basic types like string, number, and boolean. These are great for simple validations.

But real-world data is rarely simple! We often deal with complex structures like user profiles, product lists, or nested configurations.

Today, we'll dive into defining schemas for these more intricate data types, making your tRPC APIs even more robust.

Crafting Object Schemas

The z.object() method is your go-to for validating JavaScript objects. You define each property's schema within it.

  • Each key in the object corresponds to a property in your data.
  • The value for each key is another Zod schema, defining that property's type and rules.
  • By default, all properties defined in z.object() are required.

Let's see how to define a schema for a simple user object:

import { z } from 'zod';

const UserProfileSchema = z.object({
  username: z.string().min(3),
  email: z.string().email(),
  age: z.number().int().positive()
});

Running an Object Schema

To validate data against an object schema, you use the .parse() method. If the data doesn't match, it throws a ZodError.

Try running this example to see valid and invalid object data in action!

import { z } from 'zod';

const UserProfileSchema = z.object({
  username: z.string().min(3, "Username must be at least 3 chars"),
  email: z.string().email("Invalid email format"),
  age: z.number().int().positive("Age must be a positive integer")
});

function validateUser(userData: unknown) {
  try {
    const parsedUser = UserProfileSchema.parse(userData);
    console.log("Validation Success:", JSON.stringify(parsedUser));
  } catch (error: any) {
    console.log("Validation Error:", error.issues[0].message);
  }
}

console.log("--- Valid User ---");
validateUser({
  username: "coderKid",
  email: "kid@example.com",
  age: 12
});

console.log("\n--- Invalid User (Age) ---");
validateUser({
  username: "coderKid",
  email: "kid@example.com",
  age: -5
});

Nesting Objects for Complexity

Applications often have data that's structured in a hierarchical way. Zod handles this beautifully by allowing you to nest object schemas.

You can define an object schema, and then use it as the type for a property within another object schema. This keeps your schemas organized and reusable.

Here's how you might define a ShippingAddress schema and nest it within a OrderSchema:

import { z } from 'zod';

const ShippingAddressSchema = z.object({
  street: z.string().min(5),
  city: z.string().min(2),
  zipCode: z.string().regex(/^\d{5}(-\d{4})?$/)
});

const OrderSchema = z.object({
  orderId: z.string().uuid(),
  items: z.array(z.string()), // Array of item IDs
  address: ShippingAddressSchema // Nested object!
});

Working with Array Schemas

When you need to validate a list of items, z.array() comes to the rescue. It takes another Zod schema as its argument, defining the type of each element in the array.

You can validate arrays of basic types (like strings or numbers) or even arrays of complex objects.

  • z.array(z.string()): An array where every element must be a string.
  • z.array(z.object({...})): An array where every element must conform to a specific object schema.
import { z } from 'zod';

const TagSchema = z.string().min(2).max(20);
const TagsArraySchema = z.array(TagSchema).min(1).max(5);

const ProductSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(3),
  price: z.number().positive(),
  tags: TagsArraySchema // Array of strings (tags)
});

Runnable Array Schema Example

Let's put z.array() to the test. This example defines a schema for an array of numbers and then tries to validate both a valid and an invalid array.

Notice how you can chain methods like .min() and .max() directly onto the array schema itself to enforce array length constraints.

import { z } from 'zod';

const NumberListSchema = z.array(z.number()).min(2, "Must have at least 2 numbers").max(5, "Cannot have more than 5 numbers");

function validateNumberList(listData: unknown) {
  try {
    const parsedList = NumberListSchema.parse(listData);
    console.log("Validation Success:", JSON.stringify(parsedList));
  } catch (error: any) {
    console.log("Validation Error:", error.issues[0].message);
  }
}

console.log("--- Valid List ---");
validateNumberList([10, 20, 30]);

console.log("\n--- Invalid List (Too Short) ---");
validateNumberList([5]);

console.log("\n--- Invalid List (Wrong Type) ---");
validateNumberList([1, "two", 3]);

Unions and Enums for Choices

Sometimes, a property can have one of several possible types or values. Zod provides z.union() and z.enum() for these scenarios.

  • z.union([schema1, schema2]): Allows a value to match any one of the provided schemas. E.g., a status could be a string or a number.
  • z.enum(['val1', 'val2']): Restricts a string value to be one of a predefined set of literal strings. This is perfect for fixed categories or states.
import { z } from 'zod';

const IDSchema = z.union([z.string().uuid(), z.number().int().positive()]);

const StatusEnum = z.enum(['pending', 'processing', 'completed', 'failed']);

const TaskSchema = z.object({
  taskId: IDSchema, // Could be UUID string or positive integer
  description: z.string(),
  status: StatusEnum // Must be one of 'pending', 'processing', etc.
});

Custom Validation with .refine()

Zod's built-in validators cover many cases, but what if you have a unique rule? The .refine() method lets you add custom validation logic to any schema.

It takes two arguments:

  • A predicate function that returns true for valid data, false otherwise.
  • An error message string or an object with a custom message.

.refine() runs after all other schema validations, so you can be sure the data has the correct basic type and structure first.

import { z } from 'zod';

const PasswordSchema = z.string()
  .min(8, "Password must be at least 8 characters long")
  .refine(password => /[A-Z]/.test(password), "Password must contain at least one uppercase letter")
  .refine(password => /[0-9]/.test(password), "Password must contain at least one number");

const UserLoginSchema = z.object({
  email: z.string().email(),
  password: PasswordSchema
});

Running Custom Refine Example

Let's test a schema with a custom .refine() rule. We'll ensure a given date string is in the future.

This shows how powerful .refine() can be for enforcing business logic that isn't covered by standard type checks.

import { z } from 'zod';

const FutureDateSchema = z.string().datetime()
  .refine(
    (dateString) => new Date(dateString) > new Date(),
    "Date must be in the future"
  );

function validateFutureDate(dateInput: unknown) {
  try {
    const parsedDate = FutureDateSchema.parse(dateInput);
    console.log("Validation Success:", parsedDate);
  } catch (error: any) {
    console.log("Validation Error:", error.issues[0].message);
  }
}

console.log("--- Valid Future Date ---");
const future = new Date();
future.setDate(future.getDate() + 1);
validateFutureDate(future.toISOString());

console.log("\n--- Invalid Past Date ---");
const past = new Date();
past.setDate(past.getDate() - 1);
validateFutureDate(past.toISOString());

Optional Properties & Defaults

Not every property in an object is always required. Zod helps you mark properties as optional and even provide default values.

  • .optional(): Makes a property optional. If it's missing, Zod won't throw an error.
  • .nullable(): Allows a property to be null.
  • .default(value): Provides a fallback value if the property is missing or undefined.

Using these can make your schemas more flexible and handle partial data gracefully.

import { z } from 'zod';

const UserSettingsSchema = z.object({
  theme: z.enum(['light', 'dark']).default('light'), // Default to 'light'
  notifications: z.boolean().optional(), // Optional boolean
  bio: z.string().max(200).nullable().optional() // Optional, can be null
});

Quick Check on Zod Schemas

You've learned how to define object and array schemas, use unions/enums, and even add custom validation. Which of the following statements about Zod's complex schemas is TRUE?

Recap: Mastering Complex Schemas

Great job! You've taken a significant leap in your ability to define robust data validations with Zod.

We covered:

  • z.object() for structured data, including nesting.
  • z.array() for lists of items.
  • z.union() and z.enum() for handling multiple possible types or predefined values.
  • .refine() for powerful custom validation rules.
  • Making properties optional, nullable, and setting defaults.

These tools are essential for building secure and predictable tRPC APIs. Next, we'll integrate these Zod schemas directly into your tRPC procedures!

자주 묻는 질문

“복잡한 Zod 스키마 정의” 강의는 무료인가요?

네 — “복잡한 Zod 스키마 정의” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 tRPC End-to-End Type Safe APIs 강의 전체를 잠금 해제할 수 있습니다. tRPC End-to-End Type Safe APIs 강의에는 총 4개의 강의가 포함되어 있습니다.

“복잡한 Zod 스키마 정의”에서 뭘 배우나요?

객체, 배열, 사용자 지정 검증 규칙을 위한 고급 Zod 스키마를 만드는 방법을 배웁니다. 브라우저에서 직접 실행하는 실습 코드로 tRPC End-to-End Type Safe APIs을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

tRPC End-to-End Type Safe APIs을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 tRPC End-to-End Type Safe APIs은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“복잡한 Zod 스키마 정의” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 tRPC End-to-End Type Safe APIs 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 tRPC End-to-End Type Safe APIs 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Zod 스키마 소개
  2. 복잡한 Zod 스키마 정의
  3. tRPC 절차에 Zod 연동
  4. Zod 데이터 변환과 세부 검증
← tRPC End-to-End Type Safe APIs(으)로 돌아가기