2026-04-30 19:32:10 +03:00
---
title: GET-хуки REST-клиента
description: Прозрачные SWR-обёртки над GET-методами REST-клиента.
2026-05-08 08:21:34 +03:00
keywords: [rest, swr, get-хуки, client components, infra]
2026-04-30 19:32:10 +03:00
---
# GET-хуки REST-клиента
GET-хуки REST-клиента — прозрачные SWR-обёртки над GET-методами API-клиента. Они нужны, чтобы Client Components получали данные с кешированием, дедупликацией и ревалидацией, не работая с `useSWR` напрямую.
## Где лежат
GET-хуки принадлежат REST-клиенту конкретного сервиса и живут рядом с ним:
```text
2026-05-08 08:21:34 +03:00
src/infra/
2026-04-30 19:32:10 +03:00
└── pet-store-api/
├── client.ts
├── generated/
├── hooks/
│ ├── use-get-pet-list.hook.ts
│ ├── use-get-pet-detail.hook.ts
│ └── index.ts
└── index.ts
```
## Контракт
- Один GET-хук = один GET-метод клиента.
- Имя GET-хука начинается с `useGet` : `useGetPetList` , `useGetPetDetail` .
- Имя файла начинается с `use-get` : `use-get-pet-list.hook.ts` .
- Хук принимает только параметры GET-метода и `config?: SWRConfiguration` .
- Что передали хуку, то он передаёт в GET-метод.
- Внутри только SWR-механика: key, fetcher, `useSWR` , `config` .
- Хук возвращает тип ответа API: generated-тип или DTO из `types/` .
- Хук не объединяет несколько запросов.
- Хук не маппит DTO в доменную модель.
- Хук не вычисляет бизнес-флаги: `isAuth` , `canEdit` , `hasAccess` , `hasPets` .
- Хук не вызывает тосты, модалки, редиректы и не пишет UI-состояние.
## Пример списка
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/hooks/use-get-pet-list.hook.ts
2026-04-30 19:32:10 +03:00
import useSWR from 'swr'
import type { SWRConfiguration } from 'swr'
import { petStoreApi } from '../client'
import type { Pet } from '../generated/pet-store-api.generated'
export type PetStatus = 'available' | 'pending' | 'sold'
export const getPetListKey = (status: PetStatus) =>
['pet-store-api', 'pet', 'list', status] as const
/**
* Получение списка питомцев по статусу.
*/
export const useGetPetList = (status: PetStatus | null, config?: SWRConfiguration) => {
const isReady = status !== null
const key = isReady ? getPetListKey(status) : null
const fetcher = () => petStoreApi.pet.findPetsByStatus({ status })
return useSWR< Pet [ ] > (key, fetcher, config)
}
```
Функция `getPetListKey` нужна, чтобы один и тот же SWR-ключ использовался внутри GET-хука и при передаче начальных данных через `SWRConfig fallback` .
Пример начальных данных для клиентского хука:
```tsx
import type { ReactNode } from 'react'
import { SWRConfig, unstable_serialize } from 'swr'
import {
getPetListKey,
petStoreApi,
2026-05-08 08:21:34 +03:00
} from 'infra/pet-store-api'
2026-04-30 19:32:10 +03:00
export default function PetsLayout({ children }: { children: ReactNode }) {
const petsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
return (
< SWRConfig
value={{
fallback: {
[unstable_serialize(getPetListKey('available'))]: petsPromise,
},
}}
>
{children}
< / SWRConfig >
)
}
```
Клиентский компонент при этом ничего не знает про preload/fallback и продолжает вызывать обычный хук:
```tsx
const { data: pets } = useGetPetList('available')
```
## Пример detail-запроса
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/hooks/use-get-pet-detail.hook.ts
2026-04-30 19:32:10 +03:00
import useSWR from 'swr'
import type { SWRConfiguration } from 'swr'
import { petStoreApi } from '../client'
import type { Pet } from '../generated/pet-store-api.generated'
export const getPetDetailKey = (id: number) =>
['pet-store-api', 'pet', 'detail', id] as const
/**
* Получение питомца по идентификатору.
*/
export const useGetPetDetail = (id: number | null, config?: SWRConfiguration) => {
const isReady = id !== null
const key = isReady ? getPetDetailKey(id) : null
const fetcher = () => petStoreApi.pet.getPetById(id)
return useSWR< Pet > (key, fetcher, config)
}
```
## Отложенный запрос через `null`
GET-хук может принимать `null` для обязательного параметра. `null` означает, что параметр ещё не готов и запрос выполнять нельзя.
Внутри хука это выражается через `isReady` : если параметр не готов, ключ SWR становится `null` , и SWR не вызывает fetcher.
```ts
const isReady = id !== null
const key = isReady ? getPetDetailKey(id) : null
```
`null` не передаётся в метод клиента. Key-функция принимает только готовые параметры, поэтому её можно безопасно использовать для начальных данных через `SWRConfig fallback` .
Для числовых идентификаторов не используйте проверку `if (id)` : значение `0` тоже валидное число. Проверяйте явно: `id !== null` .
## Экспорт
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/hooks/index.ts
2026-04-30 19:32:10 +03:00
export { getPetListKey, useGetPetList } from './use-get-pet-list.hook'
export type { PetStatus } from './use-get-pet-list.hook'
export { getPetDetailKey, useGetPetDetail } from './use-get-pet-detail.hook'
```
```ts
2026-05-08 08:21:34 +03:00
// src/infra/pet-store-api/index.ts
2026-04-30 19:32:10 +03:00
export { petStoreApi } from './client'
export type { Pet } from './generated/pet-store-api.generated'
export * from './hooks'
```
2026-05-08 08:21:34 +03:00
## Где заканчивается infra
2026-04-30 19:32:10 +03:00
```ts
2026-05-08 08:21:34 +03:00
// Хорошо: infra, прозрачный GET-хук
2026-04-30 19:32:10 +03:00
const { data: pets } = useGetPetList('available')
```
```ts
// Хорошо: business, доменная интерпретация
export const useAvailablePets = () => {
const query = useGetPetList('available')
return {
...query,
hasPets: Boolean(query.data?.length),
}
}
```
`hasPets` — не часть GET-запроса, поэтому он не добавляется в `useGetPetList` .
## Что запрещено
```ts
// Плохо — useSWR в компоненте
const { data } = useSWR(
['pet-store-api', 'pet', 'list', status],
() => petStoreApi.pet.findPetsByStatus({ status }),
)
2026-05-08 08:21:34 +03:00
// Плохо — несколько GET внутри infra-хука
2026-04-30 19:32:10 +03:00
export const usePetDashboard = () => {
const available = useGetPetList('available')
const sold = useGetPetList('sold')
return { available, sold }
}
// Плохо — бизнес-флаг внутри GET-хука REST-клиента
export const useGetPetList = (status: PetStatus) => {
const query = useSWR(...)
return {
...query,
hasPets: Boolean(query.data?.length),
}
}
```
Подробное потребление таких хуков описано в стратегии [Клиентский GET-хук ](../strategies/client-get-hook.md ).