Как связать в один проект Frontend на React, менеджер состояния, GraphQL и гексагональный сервер на Backend

Ответ

Для связки React с GraphQL и бэкендом в гексагональной архитектуре:

  1. React + Apollo Client:
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://your-api/graphql',
  cache: new InMemoryCache()
});

function App() {
  return (
    <ApolloProvider client={client}>
      <YourComponents />
    </ApolloProvider>
  );
}
  1. Структура проекта:
/src
  /features      # модули по бизнес-логике
  /shared        # общие компоненты/хуки
  /api           # GraphQL queries/mutations
  /store         # Zustand/Redux для локального состояния
  1. Гексагональный бэкенд:
  • GraphQL выступает как адаптер, преобразует запросы в вызовы доменных сервисов
  • Домен (ядро) не зависит от GraphQL/HTTP
  • Для типизации используйте GraphQL Code Generator
  1. Советы:
  • Изолируйте GraphQL-зависимости в API слое
  • Используйте React Query для кэширования простых REST эндпоинтов
  • TypeScript для end-to-end типизации между фронтом и бэком

Ответ 18+ 🔞

А, ну ты про это, про связку React с GraphQL и бэкендом в этой вашей гексагональной архитектуре. Давай разберем, как это всё склеить, чтобы не получилось говно, которое потом переписывать три года.

Смотри, на фронте сейчас модно React + Apollo Client использовать. Это как взять хороший, заточенный инструмент, а не пытаться выстругать GraphQL клиент из палки и веревки. Вот тебе базовый пример, как это завести:

import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://your-api/graphql',
  cache: new InMemoryCache()
});

function App() {
  return (
    <ApolloProvider client={client}>
      <YourComponents />
    </ApolloProvider>
  );
}

Вот и всё, блядь. Обернул приложение в провайдер — и теперь любой компонент может запрашивать данные через GraphQL. Красота, а не жизнь.

Теперь про структуру проекта. Не надо всё сваливать в одну кучу, как у мартышлюшки в клетке. Организуй по смыслу:

/src
  /features      # Вот тут живут модули по бизнес-логике. Каждый фич-модуль — свой мирок.
  /shared        # Общие штуки, которые везде ссут: компоненты, хуки, утилиты.
  /api           # Тут вся твоя GraphQL-магия: queries, mutations, типы. Изолируй эту зависимость здесь!
  /store         # Если нужно локальное состояние (Zustand, Redux), пусть живёт тут.

Главный принцип — изоляция, ёпта. GraphQL — это просто способ поговорить с сервером, а не основа всей твоей вселенной. Засунул всю работу с API в отдельный слой — и спи спокойно.

А теперь самое интересное — гексагональный бэкенд. Тут многие так охуевают, когда начинают вникать. Смысл в чём:

  • GraphQL Schema & Resolvers — это твой адаптер, один из многих. Его задача — принять запрос от фронта, разобрать его, и позвать нужный метод в доменном сервисе. Он не должен содержать бизнес-логику! Он как переводчик.
  • Домен (ядро) — вот тут живёт вся суть твоего приложения: бизнес-правила, сущности, сервисы. Этот слой вообще не должен знать, что его дергают через GraphQL, REST, gRPC или телепатию. Он независим, как хуй с горы.
  • GraphQL Code Generator — вот это, блядь, must have. Он возьмёт твою GraphQL-схему с бэка и сгенерирует для фронта готовые TypeScript-типы и React-хуки для запросов. End-to-end типизация, ёбана! Написал запрос на фронте — и сразу видишь, какие поля доступны, что возвращается. Ошибки на этапе компиляции, а не в рантайме. Волшебство, а не инструмент.

И пара советов, чтобы не наступить на грабли:

  • Изолируй GraphQL-зависимости в API слое на фронте. Твой компонент не должен импортировать @apollo/client напрямую. Пусть он вызывает кастомный хук из api/, который внутри использует Apollo. Потом захочешь сменить клиент — перепишешь один слой, а не тысячу компонентов.
  • Если в твоём бэкенде, кроме GraphQL, есть ещё и простые REST эндпоинты (для файлов, например), не городи огород с Apollo для них. Возьми React Query (TanStack Query). Он для такого — идеальный инструмент, кэширование из коробки, обновление фона — красота.
  • TypeScript — это не опция, это обязательное условие для выживания. Особенно когда фронт и бэк говорят на одном языке типов благодаря Code Generator. Это ж как мост между двумя берегами построить, а не вплавь каждый раз перебираться.

Короче, суть в чём: разделяй ответственность, изолируй зависимости, используй правильные инструменты для задач. Тогда и архитектура будет чистой, и код поддерживаемым, и жизнь — прекрасной. Ну, или хотя бы не такой ебучей.