Skip to content

FEEDBACK-327: перевести бизнес-валидацию с valibot на zod - #16

Merged
mokevnin merged 1 commit into
mainfrom
feedback-327-zod
Aug 17, 2026
Merged

FEEDBACK-327: перевести бизнес-валидацию с valibot на zod#16
mokevnin merged 1 commit into
mainfrom
feedback-327-zod

Conversation

@mokevnin

Copy link
Copy Markdown
Contributor

Курс js_rest_api уходит от TypeBox к генерации через hey-api, а бизнес-слой идёт на zod. Эталон переезжает первым, потому что уроки пишутся по нему.

Что изменилось

  • valibot → zod в validators/, rules/unique.ts и обработчике ошибок app.ts (ValiErrorz.ZodError).
  • openapi-ts.config.ts: добавлен плагин zod, поэтому валидаторы расширяют сгенерированную схему (zUserCreateDto.extend) вместо своей копии контракта.
  • unique стал обычным предикатом для .refine(), то есть подключается к любой строковой схеме.

Дефект, который тесты не видели

POST /users отдавал 201 и сохранял пользователя с fullName: null. Валидатор объявлял только email, а object у valibot выбрасывает неизвестные поля, поэтому fullName до базы не доезжал. Существующие тесты проверяют только коды ответов, так что это не всплывало.

Проверено прогоном до и после:

до:    ответ 201 {"id":4,"fullName":"Ada Lovelace",...}   в базе fullName: null
после: ответ 201 {"id":4,"fullName":"Ada Lovelace",...}   в базе fullName: "Ada Lovelace"

Поэтому валидаторы теперь берут схемы сгенерированными: контракт один, и потерять поле нельзя.

Генерация не работала вообще

make generate-types падал: typescript@7.0.2 ломает hey-api (TypeError: Cannot read properties of undefined (reading 'AnyKeyword') — генератор ходит в ts.SyntaxKind, которого в нативном порте нет). Версия прибита к ^5.9.3; на tsc это не влияет, make check-types проходит.

Плюс генерация заканчивается форматтером: генератор пишет в своём стиле, и без этого шага make lint падает на сгенерированных файлах после каждого прогона.

Проверки

pnpm test 15/15, pnpm exec tsc без ошибок, make lint чисто.

Чего я не тронул

  • Обновление здесь @put, а уроки курса учат @patch. Контракты разошлись, но это решение про то, чему учим, а не про рефакторинг.
  • AGENTS.md устарел: описывает app.js, node:test и eslint, хотя репозиторий уже на app.ts, vitest и oxlint.
  • Ветка отрезана от main до мержа fix(lint): убрать мёртвые директивы biome-ignore #15. Конфликта по смыслу нет: fix(lint): убрать мёртвые директивы biome-ignore #15 снимал мёртвые biome-ignore из тех же трёх файлов валидаторов, а в новых версиях их и так нет.

Тикет: FEEDBACK-327

🤖 Generated with Claude Code

…ot на zod

Курс js_rest_api уходит от TypeBox к генерации через hey-api, а бизнес-слой
идёт на zod. Эталон переезжает первым, чтобы уроки писались по работающей форме.

Валидаторы больше не перечисляют поля руками, а расширяют сгенерированную
схему. Так закрыт дефект, который тесты не видели: валидатор объявлял только
email, а object у valibot выбрасывает неизвестные поля, поэтому POST /users
отдавал 201 и сохранял fullName как null. Проверено прогоном: теперь поле
доезжает до базы. Правило unique стало обычным предикатом для .refine().

Заодно починена генерация. Она не работала вовсе: typescript 7.0.2 ломает
hey-api (`Cannot read properties of undefined (reading 'AnyKeyword')`), поэтому
версия прибита к ^5.9.3. Генерация теперь заканчивается форматтером, иначе
`make lint` падает на сгенерированных файлах после каждого прогона.

Тесты 15/15, tsc и формат чисто.
@mokevnin
mokevnin merged commit 5dd3790 into main Aug 17, 2026
@mokevnin
mokevnin deleted the feedback-327-zod branch August 17, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant