Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+1 318новых вакансий за сутки·66 464вакансии открыты сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании6 021
РезюмеAIПодготовкаСтатьи
BoostТарифыBoost
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 400 кандидатов открыты к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python14 441
  • Облачные технологии10 873
  • QA вакансии3 236
  • Android1 700
  • Инженер данных1 216
  • Продакт-менеджер456

Разработка

  • Backend вакансии1 601
  • iOS1 573
  • AI вакансии776
  • Fullstack вакансии658
  • Frontend вакансии548
  • Mobile вакансии28

По стеку

  • Go7 890
  • Java5 126
  • Node.js1 605
  • Kotlin1 382
  • Rust1 310
  • .NET1 243
  • PHP535
  • C++382
  • C#353

DevOps и инфраструктура

  • Kubernetes6 204
  • Linux-инфраструктура4 735
  • DevOps вакансии4 419
  • Terraform / IaC3 428
  • Мониторинг и Observability1 570
  • CI/CD1 465
  • SRE446
  • Кибербезопасность74

Аналитика и данные

  • Аналитик данных662
  • Бизнес-аналитик625
  • Data Scientist571
  • Системный аналитик90

Другие направления

  • Проджект-менеджер146
  • UI/UX дизайн88
  • Ручное тестирование14

По регионам

  • Вакансии в США32 905
  • Вакансии в Европе14 637
  • Работа в России3 880
  • Вакансии в Канаде3 170

По формату

  • Удалённые вакансии51 011
  • Релокация в США32 905
  • Гибридная работа9 286
  • Офисная работа6 546

По уровню

  • Senior вакансии29 196
  • Middle вакансии12 901
  • Junior вакансии4 717

Сейчас нанимают

Все компании
  • Wise191 вакансия
  • Rakuten189 вакансий
  • ASML164 вакансии
  • Grab134 вакансии
  • Celonis45 вакансий
  • Spotify37 вакансий
  • Infobip28 вакансий
  • Adyen27 вакансий
  • Monzo19 вакансий
  • Darktrace17 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме tRPCВсе вопросы
tRPCMiddleКодинг

Как добавить валидацию входных данных к процедурам tRPC с помощью Zod?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Валидация входных данных добавляется через .input(zodSchema) на builder-е процедуры. tRPC автоматически проверяет входные данные и бросает BAD_REQUEST при несоответствии схеме.

Базовые примеры

// server/routers/post.ts
import { router, publicProcedure, protectedProcedure } from '../trpc';
import { z } from 'zod';

export const postRouter = router({
  // Query с примитивным входом
  getById: publicProcedure
    .input(z.string().uuid('Invalid UUID format'))
    .query(async ({ input, ctx }) => {
      // input типизирован как string
      return ctx.db.post.findUnique({ where: { id: input } });
    }),

  // Query с объектом и дефолтными значениями
  list: publicProcedure
    .input(
      z.object({
        limit: z.number().int().min(1).max(100).default(20),
        cursor: z.string().uuid().optional(),
        search: z.string().max(200).optional(),
      })
    )
    .query(async ({ input, ctx }) => {
      // input.limit — number (не undefined)
      // input.cursor — string | undefined
      const { limit, cursor, search } = input;
      return ctx.db.post.findMany({
        take: limit + 1,
        cursor: cursor ? { id: cursor } : undefined,
        where: search ? { title: { contains: search } } : undefined,
      });
    }),

  // Mutation со сложной схемой
  create: protectedProcedure
    .input(
      z.object({
        title: z.string().min(1, 'Title is required').max(200),
        body: z.string().min(10, 'Body must be at least 10 characters'),
        tags: z.array(z.string()).max(10).default([]),
        publishedAt: z.date().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      return ctx.db.post.create({
        data: {
          ...input,
          authorId: ctx.user.id,
        },
      });
    }),
});

Валидация входных данных с Zod в tRPC

tRPC нативно интегрируется с Zod: схема, переданная в .input(), автоматически валидирует входные данные до вызова resolver-функции. При ошибке валидации клиент получает структурированную ошибку с кодом BAD_REQUEST.

Переиспользование схем

// shared/schemas/post.ts — можно импортировать и на клиенте
import { z } from 'zod';

export const createPostSchema = z.object({
  title: z.string().min(1).max(200),
  body: z.string().min(10),
  tags: z.array(z.string()).max(10).default([]),
});

export type CreatePostInput = z.infer<typeof createPostSchema>;

// server/routers/post.ts
import { createPostSchema } from '@/shared/schemas/post';

export const postRouter = router({
  create: protectedProcedure
    .input(createPostSchema) // переиспользуем схему
    .mutation(({ input }) => { /* ... */ }),
});

// client/components/PostForm.tsx — та же схема для react-hook-form
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { createPostSchema, type CreatePostInput } from '@/shared/schemas/post';

export function PostForm() {
  const form = useForm<CreatePostInput>({
    resolver: zodResolver(createPostSchema), // одна схема везде
  });
}

Обработка ошибок валидации на клиенте

// client/utils/trpc-errors.ts
import { TRPCClientError } from '@trpc/client';
import type { AppRouter } from '@/server/routers/_app';

export function getValidationErrors(
  err: unknown
): Record<string, string> | null {
  if (err instanceof TRPCClientError<AppRouter>) {
    const zodError = err.data?.zodError;
    if (zodError?.fieldErrors) {
      // { title: ['Title is required'], body: ['...'] }
      return Object.fromEntries(
        Object.entries(zodError.fieldErrors).map(([k, v]) => [k, v?.[0] ?? ''])
      );
    }
  }
  return null;
}

Продвинутые возможности

// Трансформация входных данных
const createUserSchema = z.object({
  email: z.string().email().toLowerCase().trim(), // трансформация
  age: z.string().transform(Number).pipe(z.number().min(18)), // строка → число
});

// Дискриминированные объединения
const filterSchema = z.discriminatedUnion('type', [
  z.object({ type: z.literal('date'), from: z.date(), to: z.date() }),
  z.object({ type: z.literal('text'), query: z.string() }),
]);

Подводные камни

  • Zod-ошибки преобразуются в BAD_REQUEST автоматически: tRPC перехватывает ZodError — не нужно оборачивать вручную в TRPCError.
  • Без errorFormatter zodError недоступен на клиенте: нужно настроить errorFormatter в initTRPC, чтобы err.data.zodError передавался клиенту.
  • Date из JSON приходит как строка: без superjson-трансформера z.date() не разберёт ISO-строку автоматически — используйте z.coerce.date() или superjson.
  • default() влияет на тип: поле с .default([]) в TypeScript-типе не будет undefined, что может удивить при сравнении с OpenAPI-схемой.
  • Валидация не заменяет серверные проверки прав: Zod проверяет форму данных, но не бизнес-правила — проверку «пользователь не может редактировать чужой пост» делайте в процедуре.
  • z.infer с .default() и .optional(): входной тип (z.input) и выходной (z.infer) могут отличаться — используйте z.input<typeof schema> для типа формы и z.infer<typeof schema> для типа после парсинга.
  • Производительность на больших массивах: z.array(complexSchema) на тысячах элементов может заметно тормозить — рассмотрите пагинацию или упрощение схемы.

Частые вопросы на собеседовании

  • Чем tRPC отличается от REST и GraphQL? Когда стоит выбрать tRPC вместо них?
  • Как реализовать защищённые процедуры (protected procedures) с помощью middleware и context?
  • В каких типах frontend-проектов tRPC даёт реальный выигрыш, а где будет избыточен или неудачен?
  • Что такое router в tRPC и как определять процедуры (procedures)?

Типичные ошибки

  • Смешивать «валидация input через Zod» с похожим механизмом без критерия выбора.
  • Игнорировать риск: неверно оценить границы применения темы «валидация input через Zod» и получить хрупкое решение.
  • Показывать только синтаксис и не объяснять поведение в runtime или сборке.

Что проверяет интервьюер

  • Объясняет runtime-проверка пользовательских данных перед resolver.
  • Показывает на примере, как работает: TypeScript типы исчезают в runtime, поэтому tRPC procedure должна валидировать input через schema parser; Zod дает и runtime validation, и inferred TypeScript тип.
  • Называет production-нюанс и граничный случай для темы «валидация input через Zod».

Как вы знаете этот вопрос?

Проверить себя по теме tRPC →

Источники

  • https://trpc.io/docs/server/validators
←Предыдущий вопросКак реализовать защищённые процедуры (protected procedures) с помощью middleware и context?Следующий вопрос→В каких типах frontend-проектов tRPC даёт реальный выигрыш, а где будет избыточен или неудачен?

Связанные темы

tRPCapi-boundariesruntime-validation