6. Автоматическая кодогенерация
Общие принципы кодогенерации
Понятие кодогенерации
Кодогенерация - это процесс автоматического создания программного кода на основе описаний, схем или шаблонов. Вместо ручного написания повторяющихся фрагментов кода, разработчики определяют шаблоны и правила, по которым код генерируется автоматически. Это не только экономит время, но и снижает вероятность ошибок, возникающих при ручном написании однотипного кода.
В контексте GraphQL и React, кодогенерация играет особенно важную роль. GraphQL как язык запросов предоставляет строго типизированную схему, которая описывает все доступные типы данных, запросы и мутации. На основе этой схемы инструменты кодогенерации могут автоматически создавать:
- TypeScript-типы и интерфейсы — точно соответствующие структуре данных в GraphQL-схеме
- Типизированные хуки React — для выполнения запросов и мутаций с проверкой типов
- React-компоненты — для отображения, создания и редактирования данных
- Валидаторы форм — учитывающие ограничения полей из схемы
- Фрагменты GraphQL-запросов — для эффективной выборки взаимосвязанных данных
Такой подход создает бесшовную интеграцию между серверным GraphQL API и клиентским React-приложением, обеспечивая полную согласованность типов на всех уровнях. При изменении схемы GraphQL инструменты кодогенерации автоматически обновляют все сгенерированные артефакты, что позволяет быстро адаптироваться к изменениям API и избежать ошибок несоответствия типов.
Современные инструменты кодогенерации для GraphQL и React, такие как GraphQL Code Generator (используемый в проекте медицинской клиники), Apollo Codegen или Relay Compiler, поддерживают широкие возможности настройки выходного кода, позволяя интегрироваться с различными библиотеками и фреймворками, а также адаптировать генерируемый код под специфические требования проекта.
Ключевые преимущества кодогенерации:
- Снижение рутинной работы — автоматическое создание повторяющегося кода
- Типизация — генерация типов TypeScript из GraphQL-схемы
- Согласованность — поддержка единого стиля кода во всем приложении
- Скорость разработки — ускорение процесса создания типовых компонентов и запросов
В проекте данного курса используется подход, основанный на следующих этапах:
- Определение схемы GraphQL
- Генерация типов TypeScript из схемы
- Генерация GraphQL-запросов и мутаций
- Создание React-компонентов на основе типов и запросов
Проект использует библиотеку @graphql-codegen/cli для настройки процесса кодогенерации и определяет несколько конфигурационных файлов:
codegen.ts— для генерации основных типов из GraphQL-схемыgqlgen.ts— для генерации GraphQL-запросовformgen.ts— для генерации React-компонентов форм

Автоматическая кодогенерация React-приложения на основе GraphQL-схемы
- Утилита автоматической кодогенерации находится в папке
simple-ds-gql-generatorDataSpace CE и включает следующие ключевые директории:
src/- исходный код React-приложенияtsgen/- исходный код TypeScript-генератораtemplate/- шаблоны для генерации компонентов
- Выполните сборку кодогенератора:
cd tsgen
npm install
npm run build
На этом этапе происходит:
- Установка зависимостей для TypeScript-генератора
- Компиляция TypeScript-кода генератора в JavaScript
- Подготовка генератора к работе с шаблонами и утилитами
Сборка генератора создает JavaScript-файлы в директории tsgen/build/, которые затем используются в процессе кодогенерации. Эти файлы содержат функции для анализа GraphQL-схемы, формирования типов и генерации компонентов.
- Выполните кодогенерацию React-приложения:
Перейдите в корневую директорию кодогенератора (simple-ds-gql-generator) и выполните команды:
npm install
npm run get-schema
npm run allgen
Для предотвращения возможных ошибок при запуске также выполните:
export NODE_OPTIONS=--openssl-legacy-provider
И, наконец, запустите приложение:
npm start
На этом этапе происходит последовательное выполнение следующих действий:
-
npm install- установка зависимостей для React-приложения, включая:- Apollo Client для взаимодействия с GraphQL API
- React и React Router для построения пользовательского интерфейса
- Ant Design как библиотеку компонентов
- TypeScript для типизации
- GraphQL CodeGen для генерации типов и хуков
-
npm run get-schema- получение актуальной GraphQL-схемы с сервера:- Команда выполняет запрос к GraphQL API на
http://localhost:8080/graphql - Сохраняет полученную схему в файл
src/graphql/schema.graphql - Схема содержит описание всех типов, запросов и мутаций, доступных в API
- Команда выполняет запрос к GraphQL API на
-
npm run allgen- запуск всех процессов кодогенерации, который последовательно выполняет:-
graphql-codegen --config gqlgen.ts- генерация GraphQL-запросов:- Анализ GraphQL-схемы из
src/graphql/schema.graphql - Генерация запросов для каждой сущности в файлы
.graphql - Создание файлов в директории
src/graphql/__generate/ - Результат: набор типизированных GraphQL-запросов и мутаций для всех сущностей
- Анализ GraphQL-схемы из
-
graphql-codegen --config codegen.ts- генерация TypeScript-типов:- Анализ GraphQL-схемы и сгенерированных запросов
- Преобразование GraphQL-типов в TypeScript-интерфейсы и типы
- Генерация React-хуков для запросов и мутаций
- Создание файла
src/__generate/graphql-frontend.tsс типами и хуками - Результат: полный набор TypeScript-типов для всех сущностей и операций
-
graphql-codegen --config formgen.ts- генерация React-компонентов форм:- Анализ GraphQL-схемы и TypeScript-типов
- Создание компонентов для списков сущностей
- Генерация форм создания, обновления и удаления
- Формирование навигационной структуры приложения
- Создание компонентов в директории
src/components/__generate/ - Результат: полный набор React-компонентов для работы с данными
-
-
npm start- запуск локального сервера разработки:- Использует webpack-dev-server для обслуживания приложения
- Запускает приложение на
http://localhost:3000 - Обеспечивает горячую перезагрузку при изменении кода
- Протестируйте сгенерированное React-приложение
После запуска приложения можно открыть его в браузере по адресу http://localhost:3000/. Сгенерированное приложение представляет собой полноценную информационную систему с возможностями:
- Навигации по сущностям через главное меню
- Просмотра списков сущностей в табличном виде
- Создания новых записей через формы
- Редактирования существующих записей
- Удаления записей
Все компоненты взаимодействуют с GraphQL API через сгенерированные запросы и хуки, обеспечивая типизированный доступ к данным.
Структура и ключевые файлы проекта
Обзор структуры директорий
Структура сгенерированного приложения имеет следующий вид:
src/
├── __generate/ # Сгенерированные файлы GraphQL-операций и типов
│ └── graphql-frontend.ts # Основной файл с типами и хуками для GraphQL-операций
├── components/
│ ├── __generate/ # Сгенерированные React-компоненты
│ │ ├── Clinic/ # Компоненты для сущности Clinic
│ │ │ ├── ClinicAgg.tsx # Компонент-агрегатор
│ │ │ ├── Clinic/ # Директория с компонентами для Clinic
│ │ │ │ ├── ClinicBase.tsx # Базовый компонент
│ │ │ │ ├── ClinicList.tsx # Компонент списка
│ │ │ │ ├── ClinicCreate.tsx # Компонент создания
│ │ │ │ ├── ClinicCreateForm.tsx # Форма создания
│ │ │ │ ├── ClinicUpdate.tsx # Компонент обновления
│ │ │ │ ├── ClinicUpdateForm.tsx # Форма обновления
│ │ │ │ └── ClinicDelete.tsx # Компонент удаления
│ │ ├── Customer/ # Компоненты для сущности Customer
│ │ │ └── ... (аналогичная структура)
│ │ ├── ... # Другие сущности с аналогичной структурой
│ │ └── MainMenu.tsx # Главное меню приложения
│ ├── basic/ # Базовые компоненты
│ │ ├── ErrorBoundary.tsx # Компонент для обработки ошибок
│ │ ├── FormUtils.tsx # Утилиты для работы с формами
│ │ └── ... # Другие базовые компоненты
│ └── Home.tsx # Домашняя страница
├── graphql/
│ ├── __generate/ # Сгенерированные GraphQL-запросы
│ │ ├── Clinic/ # Запросы для сущности Clinic
│ │ │ ├── Clinic.graphql # Запросы для работы с Clinic
│ │ │ └── ... # Другие запросы
│ │ └── ... # Запросы для других сущностей
│ └── schema.graphql # Схема GraphQL, полученная с сервера
├── permgen.ts # Конфигурация для генерации файла разрешений
├── perm-plugin.js # Плагин для генерации JSON разрешений из GraphQL операций
├── permissions.json # Сгенерированный файл с разрешениями для всех операций
├── index.tsx # Точка входа в приложение
└── App.tsx # Корневой компонент приложения
Ключевые директории и файлы
1. Директория src/__generate/
Эта директория содержит автоматически сгенерированные TypeScript-типы и хуки для взаимодействия с GraphQL API:
- graphql-frontend.ts - централизованный файл, содержащий:
- Типы данных для всех сущностей из GraphQL-схемы
- Типизированные входные параметры для запросов и мутаций
- React-хуки для выполнения запросов (например,
useGetClinicQuery) - React-хуки для выполнения мутаций (например,
useCreateClinicMutation)
Пример фрагмента сгенерированного кода:
// Типы данных сущностей
export type Clinic = {
__typename?: 'Clinic';
id: string;
name?: Maybe<string>;
address?: Maybe<Address>;
};
// Входные параметры для запросов
export type GetClinicQueryVariables = Exact<{
id: Scalars['ID'];
}>;
// Результаты запросов
export type GetClinicQuery = {
__typename?: 'Query';
getClinic?: Maybe<{ __typename?: 'Clinic'; id: string; name?: Maybe<string> }>;
};
// Хуки для запросов
export function useGetClinicQuery(options: QueryHookOptions<GetClinicQuery, GetClinicQueryVariables>) {
return useQuery<GetClinicQuery, GetClinicQueryVariables>(GetClinicDocument, options);
}
2. Директория src/graphql/
Содержит GraphQL-схему и сгенерированные GraphQL-запросы:
-
schema.graphql - полная GraphQL-схема, полученная с сервера, которая описывает все типы, запросы и мутации.
-
__generate/ - директория с сгенерированными GraphQL-запросами для каждой сущности:
- Clinic/Clinic.graphql - запросы и мутации для сущности Clinic
- Аналогичные файлы для других сущностей
Пример сгенерированного GraphQL-запроса:
query GetClinicList {
getClinicList {
id
name
address {
city
street
flatNo
}
}
}
mutation CreateClinic($input: _CreateClinicInput!) {
createClinic(input: $input) {
id
name
}
}
3. Директория src/components/__generate/
Содержит сгенерированные React-компоненты, сгруппированные по агрегатам и сущностям:
-
MainMenu.tsx - главное навигационное меню приложения, объединяющее все агрегаты:
- Использует React Router для маршрутизации
- Содержит ссылки на все агрегаты сущностей
- Определяет структуру маршрутов приложения
-
[AggregateName]/[AggregateName]Agg.tsx - компонент-агрегатор для конкретной сущности (например,
Clinic/ClinicAgg.tsx):- Содержит подменю для навигации между компонентами агрегата
- Определяет маршруты для дочерних компонентов
-
[AggregateName]/[EntityName]/[EntityName]List.tsx - компонент для отображения списка сущностей:
- Использует хук запроса для получения данных (например,
useGetClinicListQuery) - Отображает данные в табличном виде с использованием Ant Design Table
- Содержит кнопки для навигации к компонентам создания, редактирования и удаления
- Использует хук запроса для получения данных (например,
-
[EntityName]CreateForm.tsx / [EntityName]UpdateForm.tsx - формы для создания и обновления сущностей:
- Используют Ant Design Form для создания форм
- Автоматически генерируют поля на основе типов из GraphQL-схемы
- Добавляют валидацию полей на основе обязательности в схеме
-
[EntityName]Create.tsx / [EntityName]Update.tsx / [EntityName]Delete.tsx - компоненты для операций создания, обновления и удаления:
- Инкапсулируют логику работы с соответствующими формами
- Обрабатывают обратные вызовы успешного/неуспешного завершения операций
- Реализуют навигацию после завершения операций
4. Файлы генерации разрешений
Для управления разрешениями доступа к GraphQL операциям в проекте используются следующие файлы:
- permgen.ts - конфигурационный файл для генерации разрешений:
- Определяет схему GraphQL как источник типов
- Указывает на сгенерированные GraphQL-документы в качестве источника операций
- Настраивает использование пользовательского плагина
perm-plugin.jsдля генерации файлаpermissions.json
import { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
overwrite: true,
schema: 'src/graphql/schema.graphql',
documents: 'src/graphql/__generate/**/*.graphql',
generates: {
'./permissions.json': {
plugins: ['./perm-plugin.js'],
},
},
};
-
perm-plugin.js - пользовательский плагин для GraphQL Code Generator:
- Анализирует GraphQL-операции (запросы и мутации) из сгенерированных документов
- Извлекает фрагменты GraphQL для повторного использования в операциях
- Создает JSON-структуру с разрешениями для каждой операции, включающую:
- Название операции
- Тело GraphQL-запроса с встроенными фрагментами
- Настройки безопасности (по умолчанию JWT-верификация включена, пустые проверки запрещены)
-
permissions.json - сгенерированный файл с разрешениями:
- Содержит массив объектов разрешений для всех GraphQL-операций в системе
- Каждое разрешение включает полное тело запроса с встроенными фрагментами
- Используется системой безопасности для контроля доступа к операциям
- Автоматически обновляется при изменении схемы или операций GraphQL
Пример структуры разрешения в permissions.json:
{
"name": "searchClinic",
"body": "query searchClinic($cond: String) { ... }",
"allowEmptyChecks": false,
"disableJwtVerification": false
}
5. Ключевые файлы приложения
- index.tsx - точка входа в приложение:
- Инициализирует Apollo Client для работы с GraphQL
- Рендерит корневой компонент App
- Подключает провайдеры контекста
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloProvider } from '@apollo/client';
import { client } from './cache';
import App from './App';
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
- App.tsx - корневой компонент приложения:
- Определяет общую структуру приложения
- Подключает главное меню
- Реализует основной контейнер для контента
import React from 'react';
import { Layout } from 'antd';
import { MainMenu } from './components/__generate/MainMenu';
const App: React.FC = () => {
return (
<Layout style={{ minHeight: '100vh' }}>
<MainMenu />
</Layout>
);
};
export default App;
Взаимодействие компонентов
Сгенерированные компоненты следуют единой архитектуре и взаимодействуют следующим образом:
-
Навигационная иерархия:
MainMenu.tsx→[Entity]Agg.tsx→[Entity]List.tsx→[Entity]Create.tsx/[Entity]Update.tsx/[Entity]Delete.tsx
-
Поток данных:
- Компоненты списка (
[Entity]List.tsx) получают данные через GraphQL-запросы с помощью сгенерированных хуков - Формы создания и обновления (
[Entity]CreateForm.tsx,[Entity]UpdateForm.tsx) отправляют данные через GraphQL-мутации - Компоненты обновления предварительно загружают данные сущности через запрос для предзаполнения формы
- Компоненты списка (
-
Компонентная композиция:
- Каждый компонент имеет четкую ответственность и фокусируется на конкретной задаче
- Формы инкапсулированы в отдельные компоненты, которые можно переиспользовать
- Компоненты списка предоставляют навигацию к компонентам операций (создание, обновление, удаление)
Эта структура обеспечивает четкое разделение ответственности, повторное использование кода и поддержку типизации на всех уровнях приложения.
Заключение
В данном разделе мы рассмотрели инструменты для автоматической генерации кода на основе GraphQL-схемы. Мы узнали, как использовать GraphQL Code Generator для генерации типов TypeScript и компонентов React. Мы также рассмотрели структуру и ключевые файлы сгенерированного приложения, а также взаимодействие компонентов. В следующем разделе мы познакомимся с TypeScript на примере сгенерированного в этом разделе приложения.
Ссылки
- GraphQL Code Generator - инструмент для генерации типов TypeScript и компонентов React из GraphQL-схемы
- Plop.js - генератор микрокода для создания файлов и компонентов по шаблонам
- OPENAPI Generator - генерация кода клиентов и серверов из спецификаций OpenAPI
- Type-GraphQL - создание GraphQL-схемы с использованием TypeScript и декораторов
- Prisma - ORM с генерацией TypeScript-типов из схемы базы данных
