### Install Dependencies
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/CONTRIBUTING.md
Run this command in the project root to install all necessary development dependencies.
```bash
npm install
```
--------------------------------
### Install @ronas-it/rtkq-entity-api
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Install the library using npm. For React Native, also install the optional peer dependency.
```bash
npm i @ronas-it/rtkq-entity-api
# React Native only (optional peer dependency):
npm i @react-native-community/netinfo
```
--------------------------------
### Install RTK Query Entity API
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Install the package using npm.
```sh
npm i @ronas-it/rtkq-entity-api
```
--------------------------------
### Install netinfo for React Native Refetch Listeners
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Before using `setupRefetchListeners`, install the `@react-native-community/netinfo` package for network status detection in React Native applications.
```bash
npm i @react-native-community/netinfo
```
--------------------------------
### Setup Refetch Listeners for React Native Apps
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Wraps RTK Query's setupListeners with AppState and NetInfo events for automatic query refetching on app focus or network reconnection. Throws if called on web; use RTK Query's setupListeners for web.
```typescript
import { setupRefetchListeners } from '@ronas-it/rtkq-entity-api';
import { addEventListener, fetch } from '@react-native-community/netinfo';
import ReactNative, { AppState, Platform } from 'react-native';
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
function App() {
const dispatch = useDispatch();
useEffect(() => {
const unsubscribe = setupRefetchListeners(
dispatch,
{ refetchOnFocus: true, refetchOnReconnect: true },
{ addEventListener, fetch }, // NetInfo API
{ AppState, Platform }, // React Native refs
);
return unsubscribe; // cleans up all listeners on unmount
}, []);
return ;
}
// Throws if called on web — use RTK Query's own setupListeners() for web apps.
```
--------------------------------
### Update User with Pessimistic Cache Patching
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Updates a user's information using `useUpdateMutation`. This example demonstrates automatic, pessimistic cache patching where the server response is merged into the cache after a successful update. Ensure `usersApi` is imported.
```typescript
import { usersApi } from './users-api';
function EditUserForm({ user }: { user: User }) {
const [updateUser, { isLoading }] = usersApi.useUpdateMutation();
const save = async (name: string) => {
try {
const updated = await updateUser({ id: user.id, name }).unwrap();
// All search/get queries that hold this user are automatically patched — no refetch needed.
console.log('Saved:', updated.name);
} catch (err) {
console.error('Update failed:', err.message);
}
};
}
```
--------------------------------
### Setup Automatic Refetching in React Native Apps
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Use `setupRefetchListeners` in a root component to automatically refetch data when the app regains focus or reconnects to the internet. This utility requires `@react-native-community/netinfo` and should only be used in React Native environments.
```tsx
import { addEventListener, fetch } from '@react-native-community/netinfo';
import { setupRefetchListeners } from '@ronas-it/rtkq-entity-api';
import ReactNative from 'react-native';
import { useDispatch } from 'react-redux';
function App(): ReactElement {
const dispatch = useDispatch();
useEffect(() => {
const unsubscribeRefetchListeners = setupRefetchListeners(
dispatch,
{ refetchOnFocus: true, refetchOnReconnect: true },
{ addEventListener, fetch },
ReactNative,
);
return unsubscribeRefetchListeners;
}, []);
...
}
```
--------------------------------
### fetchEntity
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Utility to fetch single entity data using GET /{baseEndpoint}/{id} with optional parameters. Useful for customizing `onQueryStarted` behavior.
```APIDOC
## fetchEntity
### Description
Fetches single entity data using `GET /{baseEndpoint}/{id}` with optional parameters.
### Method
GET
### Endpoint
`/{baseEndpoint}/{id}`
### Parameters
#### Path Parameters
- **id** (string | number) - Required - The ID of the entity to fetch.
#### Query Parameters
- **params** (object) - Optional - Additional parameters for the fetch request (e.g., `relations`).
### Request Example
```ts
const someExtendedRequest = { id: createdEntity.id, relations: ['photos'] };
const fullEntity = await someItemApi.util.fetchEntity(createdEntity.id, someExtendedRequest, { dispatch });
```
### Response
#### Success Response (200)
- **entity** (object) - The fetched entity data.
```
--------------------------------
### Search Endpoint
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a GET request to search entities with serialised query parameters from a PaginationRequest instance. Returns a PaginationResponse with a typed data array and pagination metadata.
```APIDOC
## GET /baseEndpoint
### Description
Performs a GET request to search entities with serialised query parameters from a PaginationRequest instance. Returns a PaginationResponse with a typed data array and pagination metadata.
### Method
GET
### Endpoint
/baseEndpoint
### Query Parameters
- **page** (number) - Required - The page number for pagination.
- **perPage** (number) - Required - The number of items per page.
- **orderBy** (string) - Required - The field to order the results by.
- **query** (string) - Optional - The search query string.
### Response
#### Success Response (200)
- **data** (array) - An array of entity objects.
- **pagination** (object) - Pagination metadata including currentPage and lastPage.
```
--------------------------------
### Endpoint: `get`
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a `GET` request to retrieve a specific entity by its ID. It supports optional query parameters for loading relations and deserializes the response into a typed entity instance.
```APIDOC
## Endpoint: `get`
Performs `GET /baseEndpoint/:id`. Accepts `{ id, params? }` where `params` is an optional `EntityRequest` instance for relation loading. Response is deserialised to a typed entity.
### Usage
```ts
import { usersApi } from './users-api';
import { UserEntityRequest } from './models/requests';
function UserProfile({ id }: { id: number }) {
const { data: user, isLoading, error } = usersApi.useGetQuery({
id,
params: new UserEntityRequest({ relations: ['posts', 'profile'] }),
// → GET /users/42?with[]=posts&with[]=profile
});
if (isLoading) return ;
if (error) return ;
return
{user.name} — joined {user.createdAt.toLocaleString()}
;
}
```
```
--------------------------------
### Get Endpoint Query
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a `GET` request to `baseEndpoint/:id` to retrieve a single entity. Accepts an object with `id` and optional `params` for query parameters. The response is deserialized into a typed entity.
```typescript
import { usersApi } from './users-api';
import { UserEntityRequest } from './models/requests';
function UserProfile({ id }: { id: number }) {
const { data: user, isLoading, error } = usersApi.useGetQuery({
id,
params: new UserEntityRequest({ relations: ['posts', 'profile'] }),
// → GET /users/42?with[]=posts&with[]=profile
});
if (isLoading) return ;
if (error) return ;
return
{user.name} — joined {user.createdAt.toLocaleString()}
;
```
--------------------------------
### Fetch Single Entity Data with RTKQ
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Use `fetchEntity` to retrieve single entity data via GET requests. It's useful for customizing `onQueryStarted` behavior by fetching extended entity data.
```typescript
async onQueryStarted(_, { queryFulfilled, dispatch }) {
// Wait for mutation to success:
const { data: createdEntity } = await queryFulfilled;
// Fetch extended entity data:
const someExtendedRequest = { id: createdEntity.id, relations: ['photos'] };
const fullEntity = await someItemApi.util.fetchEntity(
createdEntity.id,
someExtendedRequest,
{ dispatch }
);
// Prefill 'get' query for certain params:
someItemApi.util.upsertQueryData('get', someExtendedRequest, fullEntity);
}
```
--------------------------------
### Get Running Queries for APIs in SSR
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Resolves all in-flight RTK Query requests for specified APIs. Essential for Next.js SSR to ensure the Redux store is hydrated before serializing server-side props.
```typescript
import { getRunningQueriesForAPIs } from '@ronas-it/rtkq-entity-api';
import { store } from './store';
import { usersApi } from './users-api';
import { postsApi } from './posts-api';
// In a Next.js getServerSideProps:
export async function getServerSideProps(context) {
store.dispatch(usersApi.endpoints.search.initiate(new UserSearchRequest({ page: 1 })));
store.dispatch(postsApi.endpoints.search.initiate(new PostSearchRequest({})));
// Wait for ALL running queries across both APIs to complete:
await getRunningQueriesForAPIs(store, [usersApi, postsApi]);
return { props: { initialReduxState: store.getState() } };
}
```
--------------------------------
### api.util.clearEntityQueries
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Removes an entity from every cached list/infinite-list query containing it and decrements `pagination.total`. Does nothing to single-entity `get` cache entries.
```APIDOC
## `api.util.clearEntityQueries`
Removes an entity from every cached list/infinite-list query containing it and decrements `pagination.total`. Does nothing to single-entity `get` cache entries.
```ts
const removeApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
removeFromGroup: builder.mutation({
query: ({ userId, groupId }) => ({ method: 'delete', url: `/groups/${groupId}/users/${userId}` }),
async onQueryStarted({ userId }, apiLifecycle) {
await apiLifecycle.queryFulfilled;
await usersApi.util.clearEntityQueries(
userId,
apiLifecycle,
{ tags: [{ type: 'user', id: 'group-members' }] },
);
},
}),
}),
});
```
```
--------------------------------
### Delete Endpoint
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a DELETE request to remove an entity by its ID. On success, removes the entity from all cached lists and get queries without triggering refetches.
```APIDOC
## DELETE /baseEndpoint/:id
### Description
Performs a DELETE request to remove an entity by its ID. On success, removes the entity from all cached lists and get queries without triggering refetches.
### Method
DELETE
### Endpoint
/baseEndpoint/:id
### Response
#### Success Response (200)
- **(No content)** - Indicates successful deletion.
```
--------------------------------
### Define User Entity Request with Relations
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Extend EntityRequest to define request parameters for 'get' endpoints, supporting eager-loading of relations. Use @TransformRelations to automatically prune redundant relation paths.
```typescript
import { EntityRequest } from '@ronas-it/rtkq-entity-api';
import { Expose } from 'class-transformer';
type UserRelation = 'posts' | 'posts.comments' | 'profile';
export class UserEntityRequest extends EntityRequest {
// Inherited fields serialised to query params:
// relations → ?with[]=posts&with[]=profile
// withCount → ?with_count[]=posts
// withAvg → ?with_avg[]=posts.rating
}
// Usage:
usersApi.endpoints.get.initiate({
id: 42,
params: new UserEntityRequest({ relations: ['posts', 'posts.comments', 'profile'] }),
// TransformRelations automatically prunes 'posts' because 'posts.comments' is present
// Result: ?with[]=posts.comments&with[]=profile
});
```
--------------------------------
### Delete User with Cache Removal
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Deletes a user using `useDeleteMutation`. Upon successful deletion, the entity is automatically removed from all cached lists and get queries without triggering refetches. Ensure `usersApi` is imported.
```typescript
import { usersApi } from './users-api';
function DeleteButton({ userId }: { userId: number }) {
const [deleteUser, { isLoading }] = usersApi.useDeleteMutation();
const handleDelete = async () => {
try {
await deleteUser(userId).unwrap();
// Entity is removed from all cached search/get queries automatically.
} catch (err) {
console.error('Delete failed:', err.message);
}
};
return ;
}
```
--------------------------------
### setupRefetchListeners
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
A React Native-only utility that enhances RTK Query's `setupListeners` by integrating `AppState` (focus/blur) and `NetInfo` (online/offline) events. This ensures queries automatically refetch when the app regains foreground or network connectivity.
```APIDOC
## `setupRefetchListeners`
React Native-only utility. Wraps `setupListeners` from RTK Query with `AppState` (focus/blur) and `NetInfo` (online/offline) events so queries automatically refetch when the app regains foreground or network connectivity.
```ts
import { setupRefetchListeners } from '@ronas-it/rtkq-entity-api';
import { addEventListener, fetch } from '@react-native-community/netinfo';
import ReactNative, { AppState, Platform } from 'react-native';
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
function App() {
const dispatch = useDispatch();
useEffect(() => {
const unsubscribe = setupRefetchListeners(
dispatch,
{ refetchOnFocus: true, refetchOnReconnect: true },
{ addEventListener, fetch }, // NetInfo API
{ AppState, Platform }, // React Native refs
);
return unsubscribe; // cleans up all listeners on unmount
}, []);
return ;
}
// Throws if called on web — use RTK Query's own setupListeners() for web apps.
```
```
--------------------------------
### Dispatch storeActions.init for App Initialization
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Dispatch `storeActions.init` when the root application component mounts to perform initial actions. This action can be used in side effects to trigger logic, such as fetching user settings.
```tsx
import { store } from '@your-app/mobile/shared/data-access/store';
import { storeActions } from '@ronas-it/rtkq-entity-api';
import { ReactElement } from 'react';
function App(): ReactElement {
const dispatch = useDispatch();
useEffect(() => {
dispatch(storeActions.init());
}, []);
...
}
function Root(): ReactElement {
return (
);
}
```
```typescript
userSettingsListenerMiddleware.startListening({
actionCreator: storeActions.init,
effect: async (_, { dispatch }) => {
const language = await appStorageService.language.get();
language && dispatch(userSettingsActions.setSystemLanguage(language as LanguageCode));
},
});
```
--------------------------------
### Initialize Redux Store with storeActions.init
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Dispatch this action at root component mount to trigger application startup side-effects. Use it within listener middleware to handle initial data loading.
```typescript
import { storeActions } from '@ronas-it/rtkq-entity-api';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { userSettingsListenerMiddleware } from './listeners';
// Root App component:
function App() {
const dispatch = useDispatch();
useEffect(() => { dispatch(storeActions.init()); }, []);
return ;
}
// Listener setup:
userSettingsListenerMiddleware.startListening({
actionCreator: storeActions.init,
effect: async (_, { dispatch }) => {
const lang = await storage.get('language');
if (lang) dispatch(userSettingsActions.setLanguage(lang));
},
});
```
--------------------------------
### Bump Version and Create Tag
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/CONTRIBUTING.md
Use npm to increment the version number in package.json and automatically create a Git commit and tag.
```bash
npm version {patch|minor|major}
```
--------------------------------
### storeActions.init
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
A Redux action to be dispatched at the root component mount. It serves as a trigger for application startup side-effects like loading settings, language, and tokens.
```APIDOC
## `storeActions.init`
A Redux action dispatched at the root component mount. Use it as a trigger in listener middleware to run application startup side-effects (loading settings, language, tokens, etc.).
```ts
import { storeActions } from '@ronas-it/rtkq-entity-api';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { userSettingsListenerMiddleware } from './listeners';
// Root App component:
function App() {
const dispatch = useDispatch();
useEffect(() => { dispatch(storeActions.init()); }, []);
return ;
}
// Listener setup:
userSettingsListenerMiddleware.startListening({
actionCreator: storeActions.init,
effect: async (_, { dispatch }) => {
const lang = await storage.get('language');
if (lang) dispatch(userSettingsActions.setLanguage(lang));
},
});
```
```
--------------------------------
### Create Axios Base Query for API
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Set up a custom Axios base query for your API configuration. This involves creating an Axios instance with a base URL and then using it with the `createAxiosBaseQuery` utility.
```ts
import axios from 'axios';
import { createApiCreator, createAxiosBaseQuery } from '@ronas-it/rtkq-entity-api';
const axiosBaseQuery = createAxiosBaseQuery({
getHttpClient: () => axios.create({ baseURL: 'https://your-api-url.com' }),
});
export const createAppApi = createApiCreator({
baseQuery: axiosBaseQuery,
});
```
--------------------------------
### createStoreInitializer / AppStateFromRootReducer
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Factory for `initStore()` function, configuring the Redux store with custom middleware and enhancers. `AppStateFromRootReducer` derives the `AppState` type from the root reducer map.
```APIDOC
## `createStoreInitializer` / `AppStateFromRootReducer`
Factory that produces a reusable `initStore()` function. Configures the Redux store with `serializableCheck: false` (needed for Luxon `DateTime` values), custom middleware, and enhancers. `AppStateFromRootReducer` derives the `AppState` type from the root reducer map.
```ts
import { createStoreInitializer, AppStateFromRootReducer } from '@ronas-it/rtkq-entity-api';
import { combineReducers, Reducer } from '@reduxjs/toolkit';
import { usersApi } from './users-api';
import { authApi } from './auth-api';
const rootReducer = {
[usersApi.reducerPath]: usersApi.reducer,
[authApi.reducerPath]: authApi.reducer,
};
export type AppState = AppStateFromRootReducer;
const initStore = createStoreInitializer({
rootReducer: combineReducers(rootReducer) as Reducer,
middlewares: [usersApi.middleware, authApi.middleware],
enhancers: [], // e.g., Reactotron enhancer in development
});
export const store = initStore();
// Pass context for SSR: initStore({ req, res })
```
```
--------------------------------
### Imperatively Fetch Entity and Upsert Cache
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Demonstrates using `usersApi.util.fetchEntity` within an `onQueryStarted` handler to fetch fresh data and then `usersApi.util.upsertQueryData` to update the cache. This is useful for manual cache management after mutations. Requires `createEntityApi` and `injectEndpoints`.
```typescript
export const usersApi = createEntityApi({ ... });
// Inside a custom mutation's onQueryStarted:
const extendedApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
assignRole: builder.mutation({
query: ({ userId, roleId }) => ({ method: 'post', url: `/users/${userId}/roles/${roleId}` }),
async onQueryStarted({ userId }, { dispatch, queryFulfilled }) {
await queryFulfilled;
// Refetch fresh entity data then upsert into the 'get' cache:
const freshUser = await usersApi.util.fetchEntity(userId, {}, { dispatch });
usersApi.util.upsertQueryData('get', { id: userId }, freshUser);
},
}),
}),
});
```
--------------------------------
### Push Changes and Tags
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/CONTRIBUTING.md
After bumping the version, push the commit and associated tags to the remote repository.
```bash
git push && git push --tags
```
--------------------------------
### Run Code Checks
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/CONTRIBUTING.md
Execute linting and testing scripts to ensure code quality and correctness before committing.
```bash
lint
```
```bash
test
```
--------------------------------
### Initialize Redux Store with createStoreInitializer
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Use `createStoreInitializer` to create a Redux store initializer function. It accepts root reducer, middlewares, and enhancers. The `AppStateFromRootReducer` helper type is provided for defining the application's state type.
```typescript
export type AppState = AppStateFromRootReducer;
const rootReducer = {
[authApi.reducerPath]: authApi.reducer,
};
const middlewares = [authApi.middleware];
const initStore = createStoreInitializer({
rootReducer: rootReducer as unknown as Reducer,
middlewares,
enhancers: [...reactotronEnhancer],
});
export const store = initStore();
```
--------------------------------
### createAxiosBaseQuery
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Creates an RTK Query-compatible `baseQuery` function using Axios. It allows for custom Axios instance creation and header preparation, such as injecting authentication tokens.
```APIDOC
## createAxiosBaseQuery
Creates an RTK Query-compatible `baseQuery` function backed by Axios. Accepts a factory for the Axios instance and an optional async `prepareHeaders` hook for injecting authentication tokens or other headers.
### Usage
```ts
import axios from 'axios';
import { createAxiosBaseQuery } from '@ronas-it/rtkq-entity-api';
export const axiosBaseQuery = createAxiosBaseQuery({
getHttpClient: (api) => {
// api.extra is the thunk extra argument (e.g., Next.js request context)
return axios.create({ baseURL: 'https://api.example.com/v1' });
},
prepareHeaders: async (api) => {
// Retrieve token from Redux state
const token = (api.getState() as any).auth.accessToken;
return token ? { Authorization: `Bearer ${token}` } : {};
},
});
// Errors are normalised: { error: { code: '422', message: 'Validation failed', data: {...} } }
```
```
--------------------------------
### Search Users with Pagination
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Fetches a paginated list of users using the `useSearchQuery` hook. It constructs a `UserSearchRequest` with pagination and query parameters. Ensure `UserSearchRequest` and `usersApi` are imported.
```typescript
import { usersApi } from './users-api';
import { UserSearchRequest } from './models/requests';
function UserList() {
const [page, setPage] = useState(1);
const { data, isLoading } = usersApi.useSearchQuery(
new UserSearchRequest({ page, perPage: 20, orderBy: 'name', query: 'alice' }),
// → GET /users?page=1&per_page=20&order_by=name&query=alice
);
return (
<>
{data?.data.map((user) => )}
>
);
}
```
--------------------------------
### Create API Creator with Shared Base Query
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Returns a pre-configured `createApi` factory that enforces a shared `baseQuery`, tag types, or middleware across multiple entity APIs, reducing boilerplate.
```typescript
import { createApiCreator, createAxiosBaseQuery } from '@ronas-it/rtkq-entity-api';
import axios from 'axios';
const axiosBaseQuery = createAxiosBaseQuery({
getHttpClient: () => axios.create({ baseURL: 'https://api.example.com' }),
});
export const createAppApi = createApiCreator({
baseQuery: axiosBaseQuery,
// Any other shared createApi options (tagTypes, middleware, etc.)
});
// Later, createEntityApi can consume createAppApi instead of supplying its own baseQuery:
// createEntityApi({ baseApiCreator: createAppApi, ... })
```
--------------------------------
### Create Axios Base Query for RTK Query
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Creates a baseQuery function for RTK Query using Axios. It accepts an Axios instance factory and an optional `prepareHeaders` hook for dynamic header injection, such as authentication tokens.
```typescript
import axios from 'axios';
import { createAxiosBaseQuery } from '@ronas-it/rtkq-entity-api';
export const axiosBaseQuery = createAxiosBaseQuery({
getHttpClient: (api) => {
// api.extra is the thunk extra argument (e.g., Next.js request context)
return axios.create({ baseURL: 'https://api.example.com/v1' });
},
prepareHeaders: async (api) => {
// Retrieve token from Redux state
const token = (api.getState() as any).auth.accessToken;
return token ? { Authorization: `Bearer ${token}` } : {};
},
});
// Errors are normalised: { error: { code: '422', message: 'Validation failed', data: {...} } }
```
--------------------------------
### Endpoint: `create`
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a `POST` request to the base endpoint for creating a new entity. It supports partial entity objects or `FormData` and handles serialization/deserialization using class-transformer decorators.
```APIDOC
## Endpoint: `create`
Performs `POST /baseEndpoint`. Accepts a `Partial` or `FormData`. Serialises via `instanceToPlain` (respecting `@Expose` and `@Transform` decorators) and deserialises the response back to a typed entity instance.
### Usage
```ts
import { usersApi } from './users-api';
function CreateUserForm() {
const [createUser, { isLoading, error }] = usersApi.useCreateMutation();
const handleSubmit = async () => {
try {
const newUser = await createUser({
name: 'Alice',
phoneNumber: '+1-555-0100',
// phoneNumber is serialised as phone_number in the request body
}).unwrap();
console.log('Created:', newUser.id, newUser.createdAt.toISO());
} catch (err) {
console.error('Create failed:', err.message);
}
};
// File uploads also supported: pass FormData directly or mix File values in the partial.
}
```
```
--------------------------------
### Generate Entity API with createEntityApi
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Generate your entity API using `createEntityApi`. Specify mandatory parameters like `entityName`, `entityConstructor`, and `baseEndpoint`. Optional parameters include `baseApiCreator`, `omitEndpoints`, `entityGetRequestConstructor`, and `entitySearchRequestConstructor`.
```ts
import { createEntityApi } from '@ronas-it/rtkq-entity-api';
import { createAppApi } from 'your-project/utils';
import { User, UserEntityRequest, UserSearchRequest } from 'your-project/models';
export const usersApi = createEntityApi({
// Mandatory params
entityName: 'user', // An entity name. Must by unique
entityConstructor: User, // The entity model class constructor defined above
baseEndpoint: '/users', // Endpoint, relative to base URL configured in the API creator
// Optional params
baseApiCreator: createAppApi, // The APIs creator from above that shares configuration for new APIs
omitEndpoints: ['create', 'update', 'delete'], // Array to specify unimplemented endpoints
entityGetRequestConstructor: UserEntityRequest // Request constructor for 'get' endpoint. Defaults to EntityRequest
entitySearchRequestConstructor: UserSearchRequest, // Request constructor for 'search' endpoint. Defaults to PaginationRequest
});
```
--------------------------------
### api.util.handleEntityUpdate
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
High-level helper for `onQueryStarted` that wraps `patchEntityQueries`. Supports optimistic updates with automatic rollback on error.
```APIDOC
## `api.util.handleEntityUpdate`
High-level helper for `onQueryStarted` that wraps `patchEntityQueries`. Pass `optimistic: true` for immediate UI update with automatic rollback on error; default is pessimistic (waits for server response).
```ts
const usersApi = createEntityApi({ ... });
const extApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
deactivate: builder.mutation({
query: (id) => ({ method: 'put', url: `/users/${id}/deactivate` }),
async onQueryStarted(id, apiLifecycle) {
// Optimistic: immediately show user as inactive; roll back if request fails
await usersApi.util.handleEntityUpdate(
{ id, isActive: false },
apiLifecycle,
{ optimistic: true },
);
},
}),
}),
});
```
```
--------------------------------
### Handle Entity Updates with RTKQ
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
The `handleEntityUpdate` utility, which wraps `patchEntityQueries`, simplifies optimistic or pessimistic entity updates in `onQueryStarted` for tag-connected queries.
```typescript
markAsFavorite: builder.mutation({
query: (id) => ({
method: 'put',
url: `items/${id}/favorite`
}),
async onQueryStarted(id, apiLifecycle}) {
// Perform optimistic entity update:
await someItemApi.util.handleEntityUpdate({ id, isFavorite: true }, apiLifecycle, { optimistic: true });
// Or perform pessimistic entity update for specific tags:
await someItemApi.util.handleEntityUpdate({ id, isFavorite: true }, apiLifecycle);
}
})
```
--------------------------------
### Handle Entity Updates with handleEntityUpdate
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
A high-level helper for `onQueryStarted` that simplifies entity updates. Pass `optimistic: true` for immediate UI updates with automatic rollback on error.
```typescript
const usersApi = createEntityApi({ ... });
const extApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
deactivate: builder.mutation({
query: (id) => ({ method: 'put', url: `/users/${id}/deactivate` }),
async onQueryStarted(id, apiLifecycle) {
// Optimistic: immediately show user as inactive; roll back if request fails
await usersApi.util.handleEntityUpdate(
{ id, isActive: false },
apiLifecycle,
{ optimistic: true },
);
},
}),
}),
});
```
--------------------------------
### Handle Entity Deletes with RTKQ
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Use `handleEntityDelete`, internally using `clearEntityQueries`, for optimistic or pessimistic entity deletion from search-like queries connected by tags within `onQueryStarted`.
```typescript
removeFromFavorite: builder.mutation({
query: (id) => ({
method: 'delete',
url: `items/${id}/favorite`
}),
async onQueryStarted(id, apiLifecycle}) {
// Perform optimistic entity delete:
await someItemApi.util.handleEntityDelete(arg, apiLifecycle, { optimistic: true });
// Perform delete pessimistically for specific tags:
await someItemApi.util.handleEntityDelete(arg, apiLifecycle, { tags: [{ type: 'item', id: 'favorites' }] });
}
})
```
--------------------------------
### Create Endpoint Mutation
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Performs a `POST` request to the `baseEndpoint` for creating a new entity. Accepts a partial entity or `FormData`, serializes using `instanceToPlain`, and deserializes the response to a typed entity.
```typescript
import { usersApi } from './users-api';
function CreateUserForm() {
const [createUser, { isLoading, error }] = usersApi.useCreateMutation();
const handleSubmit = async () => {
try {
const newUser = await createUser({
name: 'Alice',
phoneNumber: '+1-555-0100',
// phoneNumber is serialised as phone_number in the request body
}).unwrap();
console.log('Created:', newUser.id, newUser.createdAt.toISO());
} catch (err) {
console.error('Create failed:', err.message);
}
};
// File uploads also supported: pass FormData directly or mix File values in the partial.
```
--------------------------------
### Infinite Scrolling User List
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Implements infinite scrolling for a user list using RTK Query's `useSearchPaginatedInfiniteQuery`. This hook provides `flatData` for a merged list and `isRefetching` status. Ensure `UserSearchRequest` and `usersApi` are imported.
```typescript
import { usersApi } from './users-api';
import { UserSearchRequest } from './models/requests';
function InfiniteUserList() {
const {
flatData,
data,
isFetching,
isRefetching,
fetchNextPage,
hasNextPage,
} = usersApi.useSearchPaginatedInfiniteQuery(
new UserSearchRequest({ perPage: 20 }),
);
return (
String(u.id)}
renderItem={({ item }) => }
onEndReached={() => !isFetching && fetchNextPage()}
/>
);
}
```
--------------------------------
### createApiCreator
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Returns a pre-configured `createApi` factory. This factory ensures all APIs created with it share a common `baseQuery`, tag types, or middleware, reducing boilerplate across multiple entity APIs.
```APIDOC
## createApiCreator
Returns a pre-configured `createApi` factory that stamps every API created with it with a shared `baseQuery`, tag types, or middleware — eliminating repeated boilerplate across multiple entity APIs.
### Usage
```ts
import { createApiCreator, createAxiosBaseQuery } from '@ronas-it/rtkq-entity-api';
import axios from 'axios';
const axiosBaseQuery = createAxiosBaseQuery({
getHttpClient: () => axios.create({ baseURL: 'https://api.example.com' }),
});
export const createAppApi = createApiCreator({
baseQuery: axiosBaseQuery,
// Any other shared createApi options (tagTypes, middleware, etc.)
});
// Later, createEntityApi can consume createAppApi instead of supplying its own baseQuery:
// createEntityApi({ baseApiCreator: createAppApi, ... })
```
```
--------------------------------
### api.util.handleEntityDelete
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
High-level helper for `onQueryStarted` that wraps `clearEntityQueries`. Supports optimistic deletion with rollback on failure.
```APIDOC
## `api.util.handleEntityDelete`
High-level helper for `onQueryStarted` that wraps `clearEntityQueries`. Supports optimistic deletion with rollback on failure.
```ts
const extApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
banUser: builder.mutation({
query: (id) => ({ method: 'post', url: `/users/${id}/ban` }),
async onQueryStarted(id, apiLifecycle) {
// Pessimistic: wait for ban to succeed, then remove from all lists
await usersApi.util.handleEntityDelete(id, apiLifecycle, { optimistic: false });
},
}),
}),
});
```
```
--------------------------------
### Create Entity API with CRUD Endpoints
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
Generates a fully-typed RTK Query API with standard CRUD endpoints and extended hooks. It can optionally share a `baseQuery` via `baseApiCreator`.
```typescript
import { createEntityApi } from '@ronas-it/rtkq-entity-api';
import { createAppApi } from './api-creator';
import { User } from './models/user';
import { UserEntityRequest, UserSearchRequest } from './models/requests';
export const usersApi = createEntityApi({
entityName: 'user', // unique Redux reducer path + RTK Query tag type
baseEndpoint: '/users',
baseApiCreator: createAppApi, // shares baseQuery; alternatively pass `baseQuery` directly
entityConstructor: User,
entitySearchRequestConstructor: UserSearchRequest,
entityGetRequestConstructor: UserEntityRequest,
omitEndpoints: ['delete'], // remove endpoints your API doesn't implement
getEntityId: (user) => user.id, // default: (item) => item.id
});
// Auto-generated hooks:
// usersApi.useCreateMutation()
// usersApi.useGetQuery({ id: 1 })
// usersApi.useSearchQuery(new UserSearchRequest({ page: 1 }))
// usersApi.useSearchPaginatedInfiniteQuery(new UserSearchRequest({}))
// usersApi.useUpdateMutation()
```
--------------------------------
### Handle Entity Deletions with handleEntityDelete
Source: https://context7.com/ronasit/rtkq-entity-api/llms.txt
A high-level helper for `onQueryStarted` that wraps `clearEntityQueries`. It supports optimistic deletion with rollback on failure.
```typescript
const extApi = usersApi.injectEndpoints({
endpoints: (builder) => ({
banUser: builder.mutation({
query: (id) => ({ method: 'post', url: `/users/${id}/ban` }),
async onQueryStarted(id, apiLifecycle) {
// Pessimistic: wait for ban to succeed, then remove from all lists
await usersApi.util.handleEntityDelete(id, apiLifecycle, { optimistic: false });
},
}),
}),
});
```
--------------------------------
### Define User Entity Model
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Define your entity class by extending `BaseEntity`. Use decorators like `@Expose` for mapping API fields to class properties. Ensure a constructor that accepts partial model data.
```ts
import { BaseEntity } from '@ronas-it/rtkq-entity-api';
export class User extends BaseEntity {
name: string;
@Expose({ name: 'phone_number' }) // APIs support of class-trasformer decorators
phoneNumber: string;
constructor(model: Partial) {
super(model);
Object.assign(this, model);
}
}
```
--------------------------------
### handleEntityUpdate
Source: https://github.com/ronasit/rtkq-entity-api/blob/main/README.md
Uses `patchEntityQueries` internally and is intended for use in the `onQueryStarted` callback to perform optimistic/pessimistic updates of entity data in queries connected by tags.
```APIDOC
## handleEntityUpdate
### Description
Uses `patchEntityQueries` internally and is intended for use in the `onQueryStarted` callback to perform optimistic/pessimistic update of entity data in queries connected by tags.
### Parameters
#### Arguments
- **entityData** (object) - Required - The data to update the entity with.
- **apiLifecycle** (object) - Required - The API lifecycle object.
- **options** (object) - Optional - Configuration options.
- **optimistic** (boolean) - Optional - If true, performs an optimistic update. Defaults to false.
- **tags** (Array