Определение endpoints

Endpoints являются центральной частью конфигурации createApi и представляют собой декларативное описание всех операций взаимодействия с сервером. Каждый endpoint описывает конкретный запрос или мутацию, а также правила кэширования, инвалидации и формирования ключей кэша.

Endpoints не являются абстрактными «маршрутами API» в классическом смысле. Это функциональные описания поведения данных внутри клиентского состояния Redux Toolkit Query: как получать данные, когда считать их актуальными, как обновлять кэш и какие зависимости у этих данных.


Базовая структура объявления endpoints

Endpoints определяются внутри вызова createApi через поле endpoints, которое представляет собой функцию с параметром builder.

import { createApi, fetchBaseQuery } fr om '@reduxjs/toolkit/query/react';

export const api = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    // endpoints здесь
  })
});

builder предоставляет два основных метода:

  • builder.query — для получения данных (GET-подобные операции)
  • builder.mutation — для изменения данных (POST, PUT, DELETE и т.п.)

Query endpoints

Query endpoint описывает операцию чтения данных. Он всегда должен быть детерминированным: одинаковые входные параметры → одинаковый результат кэширования.

getUsers: builder.query({
  query: () => '/users'
})

Форма определения

Query endpoint принимает объект конфигурации:

  • query — функция, возвращающая строку или объект запроса
  • transformResponse — преобразование ответа
  • providesTags — теги для кэш-инвалидации
  • keepUnusedDataFor — время хранения данных в кэше
  • serializeQueryArgs — управление ключом кэша

Пример с параметрами:

getUserById: builder.query({
  query: (id) => `/users/${id}`
})

Mutation endpoints

Mutation endpoint описывает операции изменения состояния на сервере. В отличие от query, мутации не кэшируются как источник истины, но могут влиять на кэш query через теги.

addUser: builder.mutation({
  query: (newUser) => ({
    url: '/users',
    method: 'POST',
    body: newUser
  })
})

Особенности mutation endpoints

  • не создают постоянный кэш как query
  • возвращают состояние выполнения (loading, success, error)
  • могут инвалидировать query через invalidatesTags

Синтаксическая модель endpoint

Каждый endpoint можно представить как объект следующей логики:

  • имя endpoint → ключ в объекте
  • тип (query / mutation)
  • конфигурация поведения запроса
  • описание связей с кэшем

Пример:

endpoints: (builder) => ({
  getPosts: builder.query({
    query: () => '/posts'
  }),

  createPost: builder.mutation({
    query: (post) => ({
      url: '/posts',
      method: 'POST',
      body: post
    })
  })
})

Генерация хука из endpoint

Каждый endpoint автоматически преобразуется в React hook (при использовании @reduxjs/toolkit/query/react).

Правило именования:

  • query → useXxxQuery
  • mutation → useXxxMutation

Пример:

const { data } = useGetPostsQuery();
const [createPost] = useCreatePostMutation();

Endpoint становится связующим звеном между декларацией API и React-слоем.


Ключ кэша и параметры endpoint

RTK Query использует комбинацию имени endpoint и аргументов запроса для генерации cache key.

getUser: builder.query({
  query: (id) => `/user/${id}`
})

Внутренне это преобразуется в:

getUser(1)
getUser(2)

Каждый вызов формирует отдельную запись в кэше.


Аргументы endpoints

Аргументы endpoint — это входные данные, которые передаются в query функцию.

getProducts: builder.query({
  query: ({ category, lim it }) =>
    `/products?category=${category}&limit=${limit}`
})

Использование:

useGetProductsQuery({ category: 'books', limit: 10 });

Аргументы могут быть:

  • примитивами
  • объектами
  • массивами
  • сериализуемыми структурами

Важно: структура аргумента напрямую влияет на кэширование.


Builder.query vs Builder.mutation

builder.query

Используется для:

  • загрузки данных
  • кэширования результата
  • подписки на изменения

Характеристики:

  • идемпотентность
  • кэширование включено
  • автоматическая рефетч-логика

builder.mutation

Используется для:

  • создания данных
  • обновления данных
  • удаления данных

Характеристики:

  • отсутствие постоянного кэша
  • ручное управление триггерами
  • возможность инвалидации query

Связь endpoints через tags

Endpoints могут быть связаны через систему тегов.

getPosts: builder.query({
  query: () => '/posts',
  providesTags: ['Posts']
}),

addPost: builder.mutation({
  query: (post) => ({
    url: '/posts',
    method: 'POST',
    body: post
  }),
  invalidatesTags: ['Posts']
})

Механизм:

  • query объявляет, какие данные он предоставляет
  • mutation объявляет, какие данные он инвалидирует
  • RTK Query автоматически перезапрашивает данные

Динамические endpoints

Endpoints могут принимать параметры не только на уровне запроса, но и на уровне конфигурации.

Пример динамической логики:

getResource: builder.query({
  query: ({ type, id }) => `/${type}/${id}`
})

Такой подход позволяет использовать один endpoint для нескольких сущностей, но требует аккуратного управления кэшем.


Управление поведением endpoint

keepUnusedDataFor

Определяет время хранения данных после удаления подписчиков.

getUsers: builder.query({
  query: () => '/users',
  keepUnusedDataFor: 60
})

transformResponse

Позволяет нормализовать ответ сервера.

getUsers: builder.query({
  query: () => '/users',
  transformResponse: (response) => response.data
})

skipToken и условные endpoints

Endpoints могут быть отключены условно через skipToken:

useGetUserQuery(userId ?? skipToken);

Это предотвращает запуск запроса при отсутствии аргумента.


Endpoint как часть архитектуры состояния

Endpoints в RTK Query не являются изолированными функциями. Они формируют:

  • слой кэширования
  • слой синхронизации с сервером
  • слой управления состоянием запросов
  • систему реактивных подписок

Каждый endpoint становится узлом в графе зависимостей данных, где:

  • query → источник данных
  • mutation → триггер изменения состояния
  • tags → механизм связи узлов

Поведение при повторных вызовах endpoints

Если endpoint вызывается с теми же аргументами:

  • повторный запрос не выполняется (при наличии кэша)
  • данные берутся из store
  • возможен фоновый refetch при определённых условиях

Если аргументы изменились:

  • создаётся новый cache entry
  • старый остаётся до истечения времени хранения

Расширенные сценарии использования endpoints

Переиспользование endpoint логики

getUsers: builder.query({
  query: (params) => ({
    url: '/users',
    params
  })
})

Сложные запросы

search: builder.query({
  query: ({ q, page, sort }) => ({
    url: '/search',
    params: { q, page, sort }
  })
})

Комбинированные endpoints

updateUser: builder.mutation({
  query: ({ id, ...patch }) => ({
    url: `/users/${id}`,
    method: 'PATCH',
    body: patch
  }),
  invalidatesTags: (result, error, arg) => [
    { type: 'User', id: arg.id }
  ]
})

Поведение endpoint в жизненном цикле запроса

Endpoint проходит несколько стадий:

  • инициализация запроса
  • проверка кэша
  • выполнение baseQuery
  • получение ответа
  • запись в кэш
  • уведомление подписчиков

Каждый endpoint определяет не только URL запроса, но и участие в жизненном цикле данных внутри store.