--- title: Business-композиция description: Когда REST-данные нужно объединить или интерпретировать в бизнес-модуле. keywords: [rest, business, композиция, hooks, domain, isAuth] --- # Business-композиция Business-композиция используется, когда простого GET-метода или прозрачного GET-хука недостаточно: нужно объединить несколько источников, преобразовать DTO или вычислить доменное состояние. ## Когда использовать - Нужно объединить несколько GET-запросов. - Нужно вычислить `isAuth`, `canEdit`, `hasAccess`, `hasPets`. - Нужно преобразовать DTO в доменную модель. - Нужно спрятать бизнес-сценарий за доменным API. Такая логика не пишется в `infrastructure/`. REST-клиент остаётся прозрачным адаптером к API. ## Пример поверх одного GET-хука ```ts // src/business/pets/hooks/use-available-pets.hook.ts import { useGetPetList } from 'infrastructure/pet-store-api' /** * Доменный список доступных питомцев. */ export const useAvailablePets = () => { const query = useGetPetList('available') return { ...query, hasPets: Boolean(query.data?.length), } } ``` `useGetPetList` — infrastructure-хук. `hasPets` — бизнес-интерпретация, поэтому она появляется в `business/pets`. ## Пример композиции нескольких GET-хуков ```ts // src/business/pets/hooks/use-pets-dashboard.hook.ts import { useGetPetList } from 'infrastructure/pet-store-api' /** * Данные dashboard по питомцам. */ export const usePetsDashboard = () => { const availablePets = useGetPetList('available') const pendingPets = useGetPetList('pending') const soldPets = useGetPetList('sold') return { availablePets, pendingPets, soldPets, total: (availablePets.data?.length ?? 0) + (pendingPets.data?.length ?? 0) + (soldPets.data?.length ?? 0), } } ``` Композиция нескольких запросов не добавляется в `infrastructure/pet-store-api/hooks/`, потому что это уже сценарий потребления данных. ## Пример auth-состояния ```ts // src/business/auth/hooks/use-auth-state.hook.ts import { useGetCurrentUser } from 'infrastructure/backend-api' /** * Состояние авторизации текущего пользователя. */ export const useAuthState = () => { const currentUser = useGetCurrentUser() const user = currentUser.data return { ...currentUser, user, isAuth: Boolean(user), } } ``` `isAuth` не является частью REST-клиента. Это доменный смысл результата запроса. ## Где размещать ```text src/business/ └── pets/ ├── hooks/ │ └── use-available-pets.hook.ts ├── mappers/ │ └── map-pet-dto-to-pet.ts ├── types/ └── index.ts ``` Модуль `business/` экспортирует наружу готовый доменный API через `index.ts`. ## Что запрещено ```ts // Плохо — business-смысл внутри infrastructure-хука export const useGetPetList = (status: PetStatus) => { const query = useSWR(...) return { ...query, hasPets: Boolean(query.data?.length), } } ``` REST-модуль отвечает за доступ к API. Business-модуль отвечает за смысл этих данных в продукте.