Как в одном приложении связать React, GraphQL и гексагональный сервер?
Основы React
Связка «React + GraphQL + гексагональный сервер» складывается в три слоя, где GraphQL — входной порт сервера, а для клиента — источник данных.
Архитектура целиком
React (UI-адаптер клиента)
→ GraphQL-клиент (Apollo / urql / graphql-request + TanStack Query)
→ GraphQL API (входной адаптер сервера)
→ резолверы → use cases (ядро домена)
→ выходные порты → адаптеры (БД, внешние API)Сервер: GraphQL как driving-адаптер
- Ядро — чистые домен и use cases, ничего не знают о GraphQL.
- GraphQL-слой — адаптер: схема описывает контракт, резолверы тонкие — маппят запрос в вызов use case и результат в тип схемы:
const resolvers = {
Mutation: {
placeOrder: (_, { input }, ctx) =>
ctx.useCases.placeOrder.execute(toCommand(input)), // только маппинг
},
};- Бизнес-правила в резолверах — антипаттерн: логика утечёт из ядра.
- Инфраструктура (Postgres, платёжка) — за выходными портами; DI собирает всё в context.
Клиент: React + GraphQL-слой
- Схема — общий контракт: из неё генерируются TypeScript-типы и хуки (GraphQL Code Generator) — типобезопасность от БД до компонента.
- Данные — через клиент с кешем (Apollo/urql) или graphql-request + TanStack Query; компоненты вызывают хуки (
useOrderQuery), не зная про транспорт. - При желании гексагональности и на клиенте: GraphQL-вызовы прячутся за клиентскими портами (OrderGateway), а React использует use cases.
Мысли для ответа
Schema-first контракт между командами; тонкие резолверы; независимость ядра от GraphQL (завтра рядом можно поставить REST-адаптер на те же use cases); кодогенерация типов на клиент.
Коротко для собеседования
GraphQL — входной адаптер гексагонального сервера: тонкие резолверы вызывают use cases ядра, инфраструктура за выходными портами. React потребляет API через GraphQL-клиент с кешем и сгенерированными из схемы типами/хуками. Схема — контракт; ядро не знает о GraphQL, поэтому транспорт заменяем.