Detailed guide on RTK Query architecture (Code Splitting).
Architectural Invariant: It is forbidden to use createApi inside business modules of entities. The project uses a single caching core, divided into configuration and authorization layers. Features and entities "inject" their endpoints into the authorized core.
For correct operation of invalidation providesTags / invalidatesTags, all possible tags are collected in a centralized config.
1export const ENUM_API_TAGS = {
2 USER: "User",
3 BOOKING_ORDERS: "Booking Orders",
4 // и другие теги...
5} as const;The lowest level of network requests. No interceptors, only pure fetchBaseQuery and global tag registration.
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});A wrapper (Middleware) over the base request. It allows centralized handling of session loss (e.g., error 401) and executing logout() for the entire application.
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};Initialization of a protected API instance (usually exported from the auth entity) using a custom 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});The final stage in the target entity. We import authApi and call injectEndpoints. This code becomes the public service of the entity.
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});