name: rtk-query-api description: RTK Query createApi best practices
RTK Query - createApi
Structure
- One API slice per base URL / data source
- Define API slices in
state-manager/api.tsfiles - Export generated hooks alongside the API
// ✅ GOOD - state-manager/api.ts
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { EntityTags } from "./types";
export const myApi = createApi({
reducerPath: "myApi",
baseQuery: fetchBaseQuery({ baseUrl: "/api" }),
tagTypes: [EntityTags.Entity, EntityTags.Entities],
endpoints: (build) => ({
getEntity: build.query<Entity, string>({
query: (id) => `entities/${id}`,
providesTags: [EntityTags.Entity],
}),
}),
});
export const { useGetEntityQuery } = myApi;
Define tags as enums in state-manager/types.ts:
export enum EntityTags {
Entity = "Entity",
Entities = "Entities",
}
Endpoints
- Use
build.queryfor GET requests - Use
build.mutationfor POST/PUT/DELETE - Type both response and argument:
build.query<ResponseType, ArgType> - Use
voidfor no arguments:build.query<Data[], void>
Caching & Tags
- Define tags as enums in
types.ts - Use
providesTagson queries for cache invalidation - Use
invalidatesTagson mutations to trigger refetch - Use
keepUnusedDataForfor custom cache duration
endpoints: (build) => ({
getItems: build.query<Item[], void>({
query: () => "items",
providesTags: [ItemTags.Items],
keepUnusedDataFor: 60, // seconds
}),
addItem: build.mutation<Item, Partial<Item>>({
query: (body) => ({ url: "items", method: "POST", body }),
invalidatesTags: [ItemTags.Items],
}),
}),
Transform Responses
- Use
transformResponseto reshape API data - Use
transformErrorResponsefor custom error handling
getItems: build.query<Item[], void>({
query: () => "items",
transformResponse: (response: ApiResponse) => response.data.items,
}),
Error Handling
- Always catch errors in custom
baseQueryorqueryFn - Return
{ data }on success,{ error }on failure
// ✅ GOOD - errors are caught and returned
queryFn: async (arg) => {
try {
const data = await fetchData(arg);
return { data };
} catch (error) {
return { error: { status: "CUSTOM_ERROR", data: error } };
}
},
Registration
Register APIs in reducers/rtkQueryApi.ts:
const APIs = {
[myApi.reducerPath]: myApi,
};