id | title | sidebar_label | hide_title | description |
---|---|---|---|---|
createApi |
createApi |
createApi |
true |
RTK Query > API: createApi reference |
createApi
is the core of RTK Query's functionality. It allows you to define a set of "endpoints" that describe how to retrieve data from backend APIs and other async sources, including the configuration of how to fetch and transform that data. It generates an "API slice" structure that contains Redux logic (and optionally React hooks) that encapsulate the data fetching and caching process for you.
:::tip
Typically, you should only have one API slice per base URL that your application needs to communicate with. For example, if your site fetches data from both /api/posts
and /api/users
, you would have a single API slice with /api/
as the base URL, and separate endpoint definitions for posts
and users
. This allows you to effectively take advantage of automated re-fetching by defining tag relationships across endpoints.
This is because:
- Automatic tag invalidation only works within a single API slice. If you have multiple API slices, the automatic invalidation won't work across them.
- Every
createApi
call generates its own middleware, and each middleware added to the store will run checks against every dispatched action. That has a perf cost that adds up. So, if you calledcreateApi
10 times and added 10 separate API middleware to the store, that will be noticeably slower perf-wise.
For maintainability purposes, you may wish to split up endpoint definitions across multiple files, while still maintaining a single API slice which includes all of these endpoints. See code splitting for how you can use the injectEndpoints
property to inject API endpoints from other files into a single API slice definition.
:::
// file: src/services/types.ts noEmit
export type Pokemon = {}
// file: src/services/pokemon.ts
// Need to use the React-specific entry point to allow generating React hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type { Pokemon } from './types'
// highlight-start
// Define a service using a base URL and expected endpoints
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (build) => ({
getPokemonByName: build.query<Pokemon, string>({
query: (name) => `pokemon/${name}`,
}),
}),
})
//highlight-end
// highlight-start
// Export hooks for usage in function components, which are
// auto-generated based on the defined endpoints
export const { useGetPokemonByNameQuery } = pokemonApi
// highlight-end
createApi
accepts a single configuration object parameter with the following options:
baseQuery(args: InternalQueryArgs, api: BaseQueryApi, extraOptions?: DefinitionExtraOptions): any;
endpoints(build: EndpointBuilder<InternalQueryArgs, TagTypes>): Definitions;
extractRehydrationInfo?: (
action: UnknownAction,
{
reducerPath,
}: {
reducerPath: ReducerPath
}
) =>
| undefined
| CombinedState<Definitions, TagTypes, ReducerPath>
tagTypes?: readonly TagTypes[];
reducerPath?: ReducerPath;
serializeQueryArgs?: SerializeQueryArgs<InternalQueryArgs>;
keepUnusedDataFor?: number; // value is in seconds
refetchOnMountOrArgChange?: boolean | number; // value is in seconds
refetchOnFocus?: boolean;
refetchOnReconnect?: boolean;
summary
args
- The return value of thequery
function for a given endpointapi
- TheBaseQueryApi
object contains:signal
- AnAbortSignal
object that may be used to abort DOM requests and/or read whether the request is aborted.abort
- Theabort()
method of the AbortController attached tosignal
.dispatch
- Thestore.dispatch
method for the corresponding Redux storegetState
- A function that may be called to access the current store stateextra
- Provided as thunk.extraArgument to the configureStore getDefaultMiddleware option.endpoint
- The name of the endpoint.type
- Type of request (query
ormutation
).forced
- Indicates if a query has been forced.queryCacheKey
- The computed query cache key.
extraOptions
- The value of the optionalextraOptions
property provided for a given endpoint
export type BaseQueryFn<
Args = any,
Result = unknown,
Error = unknown,
DefinitionExtraOptions = {},
Meta = {},
> = (
args: Args,
api: BaseQueryApi,
extraOptions: DefinitionExtraOptions,
) => MaybePromise<QueryReturnValue<Result, Error, Meta>>
export interface BaseQueryApi {
signal: AbortSignal
abort: (reason?: string) => void
dispatch: ThunkDispatch<any, any, any>
getState: () => unknown
extra: unknown
endpoint: string
type: 'query' | 'mutation'
forced?: boolean
}
export type QueryReturnValue<T = unknown, E = unknown, M = unknown> =
| {
error: E
data?: undefined
meta?: M
}
| {
error?: undefined
data: T
meta?: M
}
examples
summary
See Endpoint Definition Parameters for details on individual properties.
Query endpoints (defined with build.query()
) are used to cache data fetched from the server.
You must specify either a query
field (which will use the API's baseQuery
to make a request), or a queryFn
function with your own async logic. All other fields are optional.
export type QueryDefinition<
QueryArg,
BaseQuery extends BaseQueryFn,
TagTypes extends string,
ResultType,
ReducerPath extends string = string,
> = {
query(arg: QueryArg): BaseQueryArg<BaseQuery>
/* either `query` or `queryFn` can be present, but not both simultaneously */
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>,
): MaybePromise<QueryReturnValue<ResultType, BaseQueryError<BaseQuery>>>
/* transformResponse only available with `query`, not `queryFn` */
transformResponse?(
baseQueryReturnValue: BaseQueryResult<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): ResultType | Promise<ResultType>
/* transformErrorResponse only available with `query`, not `queryFn` */
transformErrorResponse?(
baseQueryReturnValue: BaseQueryError<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): unknown
extraOptions?: BaseQueryExtraOptions<BaseQuery>
providesTags?: ResultDescription<
TagTypes,
ResultType,
QueryArg,
BaseQueryError<BaseQuery>
>
keepUnusedDataFor?: number
onQueryStarted?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryLifecycleApi,
): Promise<void>
onCacheEntryAdded?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryCacheLifecycleApi,
): Promise<void>
argSchema?: StandardSchemaV1<QueryArg>
/* only available with `query`, not `queryFn` */
rawResponseSchema?: StandardSchemaV1<BaseQueryResult<BaseQuery>>
responseSchema?: StandardSchemaV1<ResultType>
/* only available with `query`, not `queryFn` */
rawErrorResponseSchema?: StandardSchemaV1<BaseQueryError<BaseQuery>>
errorResponseSchema?: StandardSchemaV1<BaseQueryError<BaseQuery>>
metaSchema?: StandardSchemaV1<BaseQueryMeta<BaseQuery>>
}
Infinite query endpoints (defined with build.infiniteQuery()
) are used to cache multi-page data sets from the server. They have all the same callbacks and options as standard query endpoints, but also require an additional infiniteQueryOptions
field to specify how to calculate the unique parameters to fetch each page.
For infinite query endpoints, there is a separation between the "query arg" used for the cache key, and the "page param" used to fetch a specific page. For example, a Pokemon API endpoint might have a string query arg like "fire"
, but use a page number as the param to determine which page to fetch out of the results. The query
and queryFn
methods will receive a combined {queryArg, pageParam}
object as the argument, rather than just the queryArg
by itself.
export type PageParamFunction<DataType, PageParam> = (
firstPage: DataType,
allPages: Array<DataType>,
firstPageParam: PageParam,
allPageParams: Array<PageParam>,
) => PageParam | undefined | null
type InfiniteQueryCombinedArg<QueryArg, PageParam> = {
queryArg: QueryArg
pageParam: PageParam
}
export type InfiniteQueryDefinition<
QueryArg,
PageParam,
BaseQuery extends BaseQueryFn,
TagTypes extends string,
ResultType,
ReducerPath extends string = string,
> =
// Infinite queries have all the same options as query endpoints,
// but store the `{pages, pageParams}` structure, and receive an object
// with both `{queryArg, pageParam}` as the arg for `query` and `queryFn`.
QueryDefinition<
InfiniteQueryCombinedArg<QueryArg, PageParam>,
BaseQuery,
TagTypes,
InfiniteData<ResultType>
> & {
/**
* Required options to configure the infinite query behavior.
* `initialPageParam` and `getNextPageParam` are required, to
* ensure the infinite query can properly fetch the next page of data.
* `initialPageparam` may be specified when using the
* endpoint, to override the default value.
*/
infiniteQueryOptions: {
/**
* The initial page parameter to use for the first page fetch.
*/
initialPageParam: PageParam
/**
* This function is required to automatically get the next cursor for infinite queries.
* The result will also be used to determine the value of `hasNextPage`.
*/
getNextPageParam: PageParamFunction<DataType, PageParam>
/**
* This function can be set to automatically get the previous cursor for infinite queries.
* The result will also be used to determine the value of `hasPreviousPage`.
*/
getPreviousPageParam?: PageParamFunction<DataType, PageParam>
/**
* If specified, only keep this many pages in cache at once.
* If additional pages are fetched, older pages in the other
* direction will be dropped from the cache.
*/
maxPages?: number
}
}
Mutation endpoints (defined with build.mutation()
) are used to send updates to the server, and force invalidation and refetching of query endpoints.
As with queries, you must specify either the query
option or the queryFn
async method.
export type MutationDefinition<
QueryArg,
BaseQuery extends BaseQueryFn,
TagTypes extends string,
ResultType,
ReducerPath extends string = string,
Context = Record<string, any>,
> = {
query(arg: QueryArg): BaseQueryArg<BaseQuery>
/* either `query` or `queryFn` can be present, but not both simultaneously */
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>,
): MaybePromise<QueryReturnValue<ResultType, BaseQueryError<BaseQuery>>>
/* transformResponse only available with `query`, not `queryFn` */
transformResponse?(
baseQueryReturnValue: BaseQueryResult<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): ResultType | Promise<ResultType>
/* transformErrorResponse only available with `query`, not `queryFn` */
transformErrorResponse?(
baseQueryReturnValue: BaseQueryError<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): unknown
extraOptions?: BaseQueryExtraOptions<BaseQuery>
invalidatesTags?: ResultDescription<TagTypes, ResultType, QueryArg>
onQueryStarted?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
}: MutationLifecycleApi,
): Promise<void>
onCacheEntryAdded?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
}: MutationCacheLifecycleApi,
): Promise<void>
}
When defining a key like getPosts
as shown below, it's important to know that this name will become exportable from api
and be able to referenced under api.endpoints.getPosts.useQuery()
, api.endpoints.getPosts.initiate()
and api.endpoints.getPosts.select()
. The same thing applies to mutation
s but they reference useMutation
instead of useQuery
.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]
const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Posts'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
providesTags: (result) =>
result ? result.map(({ id }) => ({ type: 'Posts', id })) : [],
}),
addPost: build.mutation<Post, Partial<Post>>({
query: (body) => ({
url: `posts`,
method: 'POST',
body,
}),
invalidatesTags: ['Posts'],
}),
}),
})
// Auto-generated hooks
export const { useGetPostsQuery, useAddPostMutation } = api
// Possible exports
export const { endpoints, reducerPath, reducer, middleware } = api
// reducerPath, reducer, middleware are only used in store configuration
// endpoints will have:
// endpoints.getPosts.initiate(), endpoints.getPosts.select(), endpoints.getPosts.useQuery()
// endpoints.addPost.initiate(), endpoints.addPost.select(), endpoints.addPost.useMutation()
// see `createApi` overview for _all exports_
summary
examples
See also Server Side Rendering and Persistence and Rehydration.
summary
examples
summary
examples
summary
By default, this function will take the query arguments, sort object keys where applicable, stringify the result, and concatenate it with the endpoint name. This creates a cache key based on the combination of arguments + endpoint name (ignoring object key order), such that calling any given endpoint with the same arguments will result in the same cache key.
summary
summary
summary
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing refetchOnMountOrArgChange
to each individual hook call or similarly by passing forceRefetch: true
when dispatching the initiate
action.
:::
summary
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing refetchOnFocus
to each individual hook call or when dispatching the initiate
action.
If you specify track: false
when manually dispatching queries, RTK Query will not be able to automatically refetch for you.
:::
summary
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing refetchOnReconnect
to each individual hook call or when dispatching the initiate
action.
If you specify track: false
when manually dispatching queries, RTK Query will not be able to automatically refetch for you.
:::
summary
examples
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing onSchemaFailure
to each individual endpoint definition.
:::
summary
examples
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing catchSchemaFailure
to each individual endpoint definition.
:::
summary
examples
:::note
You can set this globally in createApi
, but you can also override the default value and have more granular control by passing skipSchemaValidation
to each individual endpoint definition.
:::
(required if no queryFn
provided)
export type query = <QueryArg>(
arg: QueryArg,
) => string | Record<string, unknown>
// with `fetchBaseQuery`
export type query = <QueryArg>(arg: QueryArg) => string | FetchArgs
summary
examples
(required if no query
provided)
summary
Called with the same arguments as baseQuery
, as well as the provided baseQuery
function itself. It is expected to return an object with either a data
or error
property, or a promise that resolves to return such an object.
See also Customizing queries with queryFn.
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>
): MaybePromise<
| {
error: BaseQueryError<BaseQuery>
data?: undefined
}
| {
error?: undefined
data: ResultType
}
>
export interface BaseQueryApi {
signal: AbortSignal
dispatch: ThunkDispatch<any, any, any>
getState: () => unknown
}
args
- The argument provided when the query itself is calledapi
- TheBaseQueryApi
object, containingsignal
,dispatch
andgetState
propertiessignal
- AnAbortSignal
object that may be used to abort DOM requests and/or read whether the request is aborted.dispatch
- Thestore.dispatch
method for the corresponding Redux storegetState
- A function that may be called to access the current store state
extraOptions
- The value of the optionalextraOptions
property provided for the endpointbaseQuery
- ThebaseQuery
function provided to the api itself
examples
(only for infiniteQuery
endpoints)
summary
The infiniteQueryOptions
field includes:
initialPageParam
: the default page param value used for the first request, if this was not specified at the usage sitegetNextPageParam
: a required callback you must provide to calculate the next page param, given the existing cached pages and page paramsgetPreviousPageParam
: an optional callback that will be used to calculate the previous page param, if you try to fetch backwards.maxPages
: an optional limit to how many fetched pages will be kept in the cache entry at a time
examples
(optional, not applicable with queryFn
)
summary
In some cases, you may want to manipulate the data returned from a query before you put it in the cache. In this instance, you can take advantage of transformResponse
.
See also Customizing query responses with transformResponse
transformResponse: (response, meta, arg) =>
response.some.deeply.nested.collection
(optional, not applicable with queryFn
)
summary
In some cases, you may want to manipulate the error returned from a query before you put it in the cache. In this instance, you can take advantage of transformErrorResponse
.
See also Customizing query responses with transformErrorResponse
transformErrorResponse: (response, meta, arg) =>
response.data.some.deeply.nested.errorObject
(optional)
Passed as the third argument to the supplied baseQuery
function
(optional, only for query endpoints)
summary
See also Providing cache data.
examples
(optional, only for mutation endpoints)
summary
See also Invalidating cache data.
examples
(optional, only for query endpoints)
Overrides the api-wide definition of keepUnusedDataFor
for this endpoint only.
summary
examples
(optional, only for query endpoints)
summary
examples
(optional, only for query endpoints)
summary
examples
(optional, only for query endpoints)
type forceRefetch = (params: {
currentArg: QueryArg | undefined
previousArg: QueryArg | undefined
state: RootState<any, any, string>
endpointState?: QuerySubState<any>
}) => boolean
summary
examples
(optional)
Available to both queries and mutations.
A function that is called when you start each individual query or mutation. The function is called with a lifecycle api object containing properties such as queryFulfilled
, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call).
Can be used in mutations
for optimistic updates.
dispatch
- The dispatch method for the store.getState
- A method to get the current state for the store.extra
-extra
as provided asthunk.extraArgument
to theconfigureStore
getDefaultMiddleware
option.requestId
- A unique ID generated for the query/mutation.queryFulfilled
- A Promise that will resolve with adata
property (the transformed query result), and ameta
property (meta
returned by thebaseQuery
). If the query fails, this Promise will reject with the error. This allows you toawait
for the query to finish.getCacheEntry
- A function that gets the current value of the cache entry.updateCachedData
(query endpoints only) - A function that accepts a 'recipe' callback specifying how to update the data for the corresponding cache at the time it is called. This usesimmer
internally, and updates can be written 'mutably' while safely producing the next immutable state.
async function onQueryStarted(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
}: MutationLifecycleApi,
): Promise<void>
async function onQueryStarted(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryLifecycleApi,
): Promise<void>
// file: notificationsSlice.ts noEmit
export const messageCreated = (msg: string) => ({
type: 'notifications/messageCreated',
payload: msg,
})
// file: api.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
import { messageCreated } from './notificationsSlice'
export interface Post {
id: number
name: string
}
const api = createApi({
baseQuery: fetchBaseQuery({
baseUrl: '/',
}),
endpoints: (build) => ({
getPost: build.query<Post, number>({
query: (id) => `post/${id}`,
async onQueryStarted(id, { dispatch, queryFulfilled }) {
// `onStart` side-effect
dispatch(messageCreated('Fetching post...'))
try {
const { data } = await queryFulfilled
// `onSuccess` side-effect
dispatch(messageCreated('Post received!'))
} catch (err) {
// `onError` side-effect
dispatch(messageCreated('Error fetching post!'))
}
},
}),
}),
})
(optional)
Available to both queries and mutations.
A function that is called when a new cache entry is added, i.e. when a new subscription for the endpoint + query parameters combination is created. The function is called with a lifecycle api object containing properties such as cacheDataLoaded
& cacheDataRemoved
, allowing code to be run when a cache entry is added, when cache data is loaded, and when the cache entry is removed (i.e. throughout the lifecycle of a cache entry).
Can be used for streaming updates.
dispatch
- The dispatch method for the store.getState
- A method to get the current state for the store.extra
-extra
as provided asthunk.extraArgument
to theconfigureStore
getDefaultMiddleware
option.requestId
- A unique ID generated for the cache entry.cacheEntryRemoved
- A Promise that allows you to wait for the point in time when the cache entry has been removed from the cache, by not being used/subscribed to any more in the application for too long or by dispatchingapi.util.resetApiState
.cacheDataLoaded
- A Promise that will resolve with the first value for this cache key. This allows you toawait
until an actual value is in the cache.
Note: If the cache entry is removed from the cache before any value has ever been resolved, this Promise will reject withnew Error('Promise never resolved before cacheEntryRemoved.')
to prevent memory leaks. You can just re-throw that error (or not handle it at all) - it will be caught outside ofcacheEntryAdded
.getCacheEntry
- A function that gets the current value of the cache entry.updateCachedData
(query endpoints only) - A function that accepts a 'recipe' callback specifying how to update the data at the time it is called. This usesimmer
internally, and updates can be written 'mutably' while safely producing the next immutable state.
async function onCacheEntryAdded(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
}: MutationCacheLifecycleApi,
): Promise<void>
async function onCacheEntryAdded(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryCacheLifecycleApi,
): Promise<void>
Endpoints can have schemas for runtime validation of query args, responses, and errors. Any Standard Schema compliant library can be used.
When used with TypeScript, schemas can also be used to infer the type of that value instead of having to declare it.
:::warning
By default, schema failures are treated as fatal, meaning that normal error handling such as tag invalidation will not be executed.
In order for schema failures to be treated as non-fatal, you must provide a catchSchemaFailure
function, to convert the schema failure into an error shape matching the base query errors.
const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
catchSchemaFailure: (error, info) => ({
status: 'CUSTOM_ERROR',
error: error.schemaName + ' failed validation',
data: error,
}),
endpoints: (build) => ({
// ...
}),
})
:::
(optional)
summary
examples
(optional)
summary
examples
(optional, not applicable with queryFn
)
summary
examples
(optional)
summary
examples
(optional, not applicable with queryFn
)
summary
examples
(optional)
summary
examples