Юрий Белк – Full stack Developer (страница 4)
– turbo решает, что можно выполнить параллельно, а что нужно последовательно.
Например, логика может быть такая:
– сначала генерируем типы из OpenAPI в packages/shared-contract,
– потом бэкенды используют эти артефакты,
– потом фронт использует клиент.
Даже если вы не используете сложные графы задач – turbo всё равно упрощает запуск “всего репо”.
2.3. Общие правила репозитория
Чтобы репо не превратилось в свалку:
1) Все внешние сервисы (Postgres/Redis и т.п.) – в /infra и docker-compose.
2) Контракт API – в одном месте (/packages/shared-contract).
3) Каждый backend должен:
– подниматься командой dev,
– отдавать OpenAPI (если фреймворк умеет),
– запускать миграции отдельной командой.
4) E2E тесты не знают, какой язык под капотом – им важен URL и контракт.
Контракт как основа: OpenAPI-first
Самая важная идея книги: контракт важнее реализации.
Мы будем строить систему так, будто бэкенд – это “плагин”. Сегодня он на NestJS, завтра на FastAPI, послезавтра на Go. Если контракт не меняется – фронт и интеграции не должны страдать.
0.3.1. Что значит OpenAPI-first
OpenAPI-first означает:
1) Сначала описываем API в openapi.yaml.
2) На основе контракта:
– генерируем клиент для фронта,
– генерируем типы/DTO (где это уместно),
– валидируем, что запросы/ответы соответствуют схеме.
3) Реализации бэкенда обязаны соответствовать контракту.
Это дисциплина, которая резко снижает хаос:
– меньше “а давай добавим поле, а фронт потом как-нибудь догадается”,
– меньше разночтений между командами,
– проще писать e2e‑тесты.
Где лежит контракт и как он выглядит
Контракт кладём в:
– /packages/shared-contract/openapi.yaml
Внутри openapi.yaml мы описываем:
– базовую информацию (title, version),
– серверы (на локалке),
– пути (/health, /users, …),
– схемы данных (DTO),
– ошибки (единый формат).
Даже если в каждом бэкенде есть автогенерация OpenAPI (NestJS Swagger, FastAPI docs, Springdoc) – источником истины остаётся наш openapi.yaml.
Автогенерация полезна, но она часто:
– зависит от аннотаций и кода,
– по-разному описывает типы,
– может “уплывать” при рефакторингах.
В книге мы будем делать наоборот: код подстраивается под контракт.
Генерация клиентов и типов
Зачем это нужно:
– фронту нужны типы запросов/ответов,
– e2e‑тестам нужны типы,
– иногда удобно генерировать серверные интерфейсы/заготовки.
Что можно генерировать:
– TypeScript клиент (например, fetch‑клиент или axios‑клиент),
– TypeScript типы DTO,
– (опционально) клиенты для других языков.
В рамках книги важно не то, какой именно генератор вы выберете, а сам принцип:
– контракт обновили → артефакты пересобрали → всё компилируется/тестируется.
Хорошая практика: хранить сгенерированный код либо:
– в packages/shared-contract/dist (и не коммитить, генерировать в CI), либо
– коммитить в репозиторий (проще для новичков, меньше магии).
Для учебной книги часто удобнее второй вариант (видно, что получилось). Для промышленной разработки обычно выбирают первый (генерация в CI).
Валидация контракта в CI
Контракт должен проверяться автоматически, иначе он быстро перестанет быть “истиной”.
Минимальный набор проверок:
1) Линт OpenAPI – формат, обязательные поля, правила стиля.
2) Валидация схемы – файл реально соответствует OpenAPI версии 3.x.