---
title: Validate All Input with Zod Schemas
impact: HIGH
impactDescription: Prevents invalid data from entering the system
tags: api, validation, zod, security
---
## Паспорт документа

- Статус документа: living standard
- Актуально на: 28 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении инженерной практики, CI/CD, архитектурных правил или локального workflow
- Область применения: внутренние rule/reference-card документы для инженерной команды
- Связанные документы:
  - [Индекс Agents](../README.md)
  - [Команды разработки](../commands.md)
  - [Инженерные принципы](../../governance/engineering-principles.md)

## Validate All Input with Zod Schemas

**Impact: HIGH**

All user input must be validated before processing. Use Zod schemas from `packages/shared` so validation rules are shared between frontend and backend.

### Shared Schema (packages/shared)

```typescript
// packages/shared/src/schemas/item.ts
import { z } from 'zod';

export const CreateItemSchema = z.object({
  name: z.string().min(3, 'Name must be at least 3 characters').max(200),
  description: z.string().min(10).max(5000).optional(),
  shortDescription: z.string().max(300).optional(),
  priceFrom: z.number().nonnegative().optional(),
  priceTo: z.number().nonnegative().optional(),
  subjectId: z.string().uuid().optional(),
  locationId: z.string().uuid().optional(),
  studyFormat: z.enum(['ONLINE', 'OFFLINE', 'HYBRID']),
  studyType: z.enum(['GROUP', 'MINI_GROUP', 'ONE_ON_ONE']).optional(),
  language: z.enum(['RU', 'UZ_LATIN', 'UZ_CYRILLIC', 'EN', 'KK', 'TG', 'ANY']).default('ANY'),
});

export type CreateItemDTO = z.infer<typeof CreateItemSchema>;
```

### Backend Validation (NestJS Pipe)

```typescript
// common/pipes/zod-validation.pipe.ts
import { PipeTransform, BadRequestException } from '@nestjs/common';
import type { ZodSchema } from 'zod';

export class ZodValidationPipe implements PipeTransform {
  constructor(private schema: ZodSchema) {}

  transform(value: unknown) {
    const result = this.schema.safeParse(value);
    if (!result.success) {
      throw new BadRequestException({
        message: 'Validation failed',
        errors: result.error.flatten().fieldErrors,
      });
    }
    return result.data;
  }
}

// Usage in controller
@Post()
async create(@Body(new ZodValidationPipe(CreateItemSchema)) dto: CreateItemDTO) {
  return this.itemService.create(dto);
}
```

### Frontend Validation (React Hook Form + Zod)

```typescript
// Using the same schema on the frontend
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { CreateItemSchema, type CreateItemDTO } from '@repo/shared';

function CreateItemForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<CreateItemDTO>({
    resolver: zodResolver(CreateItemSchema),
  });

  return <form onSubmit={handleSubmit(onSubmit)}>...</form>;
}
```

**Rules:**
- All input schemas live in `packages/shared/src/schemas/`
- Backend validates via `ZodValidationPipe` in controllers
- Frontend validates via `zodResolver` in forms
- Never trust client-side validation alone — always validate on the backend
