Детальное руководство по архитектуре RTK Query (Code Splitting).
Архитектурный инвариант: Запрещено использовать createApi внутри бизнес-модулей сущностей. Проект использует единое ядро кэширования, разделенное на слои конфигурации и авторизации. Фичи и сущности "внедряют" свои эндпоинты в авторизованное ядро.
Для корректной работы инвалидации providesTags / invalidatesTags, все возможные теги собираются в централизованный конфиг.
1export const ENUM_API_TAGS = {
2 USER: "User",
3 BOOKING_ORDERS: "Booking Orders",
4 // и другие теги...
5} as const;Самый нижний уровень сетевых запросов. Никаких перехватчиков, только чистый fetchBaseQuery и регистрация глобальных тегов.
1import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2import { ENV } from "@/shared/config";
3import { ENUM_API_TAGS } from "./tags.config";
4
5export const baseApi = createApi({
6 baseQuery: fetchBaseQuery({
7 baseUrl: ENV.VITE_API_URL,
8 credentials: "include"
9 }),
10 reducerPath: "baseApi",
11 endpoints: () => ({}),
12 tagTypes: Object.values(ENUM_API_TAGS)
13});Обертка (Middleware) над базовым запросом. Позволяет централизованно обработать потерю сессии (например, ошибку 401) и выполнить logout() на всё приложение.
1import { type BaseQueryFn, type FetchArgs, type FetchBaseQueryError, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2import { ENV } from "@/shared/config";
3import { logout } from "@/entities/user/slice/user.slice";
4
5export const authBaseQuery: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (args, api, extraOptions) => {
6 const baseQuery = fetchBaseQuery({ baseUrl: ENV.VITE_API_URL, credentials: "include" });
7 const result = await baseQuery(args, api, extraOptions);
8
9 if (result.error && result.error.status === 401) {
10 api.dispatch(logout());
11 }
12 return result;
13};Инициализация защищенного API-инстанса (обычно экспортируется из сущности auth), использующего кастомный authBaseQuery.
1import { createApi } from "@reduxjs/toolkit/query/react";
2import { ENUM_API_TAGS } from "@/shared/api/backend/tags.config";
3import { authBaseQuery } from "./auth-base-query";
4
5export const authApi = createApi({
6 baseQuery: authBaseQuery,
7 reducerPath: "authApi",
8 endpoints: () => ({}),
9 tagTypes: Object.values(ENUM_API_TAGS)
10});Финальный этап в целевой сущности. Мы импортируем authApi и вызываем injectEndpoints. Этот код и становится публичным сервисом сущности.
1import { authApi } from "@/entities/auth/api/auth.api";
2
3export const bookingOrderApi = authApi.injectEndpoints({
4 endpoints: (builder) => ({
5 getBookingOrders: builder.query<TResponse, TFilters>({
6 query: (filters) => ({ url: "/booking/orders" }),
7 providesTags: [ENUM_API_TAGS.BOOKING_ORDERS]
8 })
9 })
10});