2026-04-30 19:32:10 +03:00
---
title: Business-композиция
description: Когда REST-данные нужно объединить или интерпретировать в бизнес-модуле.
keywords: [rest, business, композиция, hooks, domain, isAuth]
---
# Business-композиция
Business-композиция используется, когда простого GET-метода или прозрачного GET-хука недостаточно: нужно объединить несколько источников, преобразовать DTO или вычислить доменное состояние.
## Когда использовать
- Нужно объединить несколько GET-запросов.
- Нужно вычислить `isAuth` , `canEdit` , `hasAccess` , `hasPets` .
- Нужно преобразовать DTO в доменную модель.
- Нужно спрятать бизнес-сценарий за доменным API.
2026-05-08 08:21:34 +03:00
Такая логика не пишется в `infra/` . REST-клиент остаётся прозрачным адаптером к API.
2026-04-30 19:32:10 +03:00
## Пример поверх одного GET-хука
```ts
// src/business/pets/hooks/use-available-pets.hook.ts
2026-05-08 08:21:34 +03:00
import { useGetPetList } from 'infra/pet-store-api'
2026-04-30 19:32:10 +03:00
/**
* Доменный список доступных питомцев.
*/
export const useAvailablePets = () => {
const query = useGetPetList('available')
return {
...query,
hasPets: Boolean(query.data?.length),
}
}
```
2026-05-08 08:21:34 +03:00
`useGetPetList` — infra-хук. `hasPets` — бизнес-интерпретация, поэтому она появляется в `business/pets` .
2026-04-30 19:32:10 +03:00
## Пример композиции нескольких GET-хуков
```ts
// src/business/pets/hooks/use-pets-dashboard.hook.ts
2026-05-08 08:21:34 +03:00
import { useGetPetList } from 'infra/pet-store-api'
2026-04-30 19:32:10 +03:00
/**
* Данные 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),
}
}
```
2026-05-08 08:21:34 +03:00
Композиция нескольких запросов не добавляется в `infra/pet-store-api/hooks/` , потому что это уже сценарий потребления данных.
2026-04-30 19:32:10 +03:00
## Пример auth-состояния
```ts
// src/business/auth/hooks/use-auth-state.hook.ts
2026-05-08 08:21:34 +03:00
import { useGetCurrentUser } from 'infra/backend-api'
2026-04-30 19:32:10 +03:00
/**
* Состояние авторизации текущего пользователя.
*/
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
2026-05-08 08:21:34 +03:00
// Плохо — business-смысл внутри infra-хука
2026-04-30 19:32:10 +03:00
export const useGetPetList = (status: PetStatus) => {
const query = useSWR(...)
return {
...query,
hasPets: Boolean(query.data?.length),
}
}
```
REST-модуль отвечает за доступ к API. Business-модуль отвечает за смысл этих данных в продукте.