Тема
Архитектура
Query Layer использует одно направление зависимостей:
mermaid
flowchart LR
UI["React UI"] --> Domain["Domain MobX store"]
Domain --> Handler["Query Layer store"]
Handler --> Api["API-функция"]
Api --> Axios["Axios client"]
Axios --> Server["Backend"]Ответ идёт обратно по той же цепочке. UI не перепрыгивает через domain store.
Transport
Transport знает общие сетевые настройки:
baseURL;- timeout;
- cookies;
- Authorization header;
- refresh token flow.
Обычно приложение создаёт publicApi и authApi в одном файле.
Transport не знает, что такое форма регистрации, список проектов или React.
API-функция
Одна API-функция соответствует одному backend endpoint:
ts
export const getUserByIdApi = (
userId: string,
config?: AxiosRequestConfig,
): Promise<AxiosResponse<User>> => {
return authApi.get<User>(`/api/v1/users/${userId}`, config)
}Она отвечает за URL, HTTP-метод, DTO и runtime-проверку ответа. Последний AxiosRequestConfig нужен для AbortSignal.
Query Layer store
Store библиотеки отвечает за техническое состояние HTTP-операции:
- запуск и отмена;
loading,status,error,data;- retry;
- cache и dedup, если выбран query API;
- lifecycle callbacks mutation;
- pagination.
Это может быть RequestStore, FetchStore, QueryStore, MutationStore или InfiniteQueryStore.
Domain store
Domain store скрывает универсальный handler:
ts
export class UserDetailsStore {
private readonly requestHandler = new FetchStore(...)
get user(): User | null {
return this.requestHandler.data ?? null
}
async fetch(userId: string): Promise<User | null> {
const response = await this.requestHandler.fetch(userId)
return response?.data ?? null
}
}Он отвечает за предметные имена, mapper формы, computed-поля и преобразование ошибки в domain error.
Если feature совсем простая и не имеет предметной логики, можно экспортировать настроенный FetchStore напрямую из data-layer. UI всё равно не должен импортировать API-функцию.
React UI
Компонент:
- хранит локальные значения полей;
- вызывает domain-методы;
- читает observable-состояние;
- отображает loading, data и error;
- освобождает локальный store при unmount.
Компонент не выбирает URL, не создаёт Axios client и не разбирает DTO backend.
QueryRuntime
QueryRuntime находится над stores и управляет общими ресурсами:
mermaid
flowchart TD
Runtime["QueryRuntime"] --> ScopeA["Application scope"]
Runtime --> ScopeB["Remote scope"]
ScopeA --> StoresA["MobX stores"]
ScopeB --> StoresB["MobX stores"]Он нужен не каждой feature. Runtime создаётся на composition root, если нужен общий cache, plugins или Module Federation.
Правило зависимостей
Допустимо:
text
UI → domain store → query-layer store → API-функция → Axios clientНе допускайте обратных импортов:
- API-функция не импортирует store;
- store не импортирует React;
- UI не импортирует API-функцию или Axios client;
- remote не получает root runtime.
Практический полный пример: Flow разработчика.