Generate type-safe React Query (TanStack Query) hooks from your service definitions for seamless API integration in React applications.
Usage
apicentric simulator generate-query --file <INPUT> --output <OUTPUT>
Arguments
Path to the Apicentric service definition YAML file to generate React Query hooks from.
Path where the generated TypeScript/JavaScript file will be written. Should have a .ts or .tsx extension.
Options
--config
string
default:"apicentric.json"
Path to the configuration file (global option).
Execution mode override: ci, development, or debug (global option).
Show what would be generated without actually creating the output file (global option).
Enable verbose output for detailed logging (global option).
--db-path
string
default:"apicentric.db"
Path to the SQLite database for simulator storage (global option).
Examples
Generate React Query hooks
apicentric simulator generate-query --file services/users.yaml --output src/hooks/useUsers.ts
Example output:
✅ Exported React Query hooks to src/hooks/useUsers.ts
Generate for multiple services
apicentric simulator generate-query --file services/products.yaml --output src/hooks/useProducts.ts
apicentric simulator generate-query --file services/orders.yaml --output src/hooks/useOrders.ts
Dry run mode
apicentric simulator generate-query --file services/api.yaml --output hooks.ts --dry-run
Example output:
🏃 Dry run: Would export React Query hooks from 'services/api.yaml' to 'hooks.ts'
Generated output
The command generates React Query hooks for:
- useQuery hooks - For GET endpoints (data fetching)
- useMutation hooks - For POST, PUT, PATCH, DELETE endpoints (data mutations)
- TypeScript types - Request and response types
- Query keys - Standardized cache keys for each endpoint
- API client - Fetch-based functions for each endpoint
Example service definition
name: users
server:
port: 8001
base_path: /api/v1
types:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
CreateUserRequest:
type: object
properties:
name:
type: string
email:
type: string
endpoints:
- path: /users
method: GET
response:
status: 200
body:
type: array
items:
$ref: "#/types/User"
- path: /users/:id
method: GET
response:
status: 200
body:
$ref: "#/types/User"
- path: /users
method: POST
request:
body:
$ref: "#/types/CreateUserRequest"
response:
status: 201
body:
$ref: "#/types/User"
- path: /users/:id
method: DELETE
response:
status: 204
Generated React Query hooks
// Generated by Apicentric
// Do not edit manually
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// Types
export interface User {
id: string;
name: string;
email: string;
}
export interface CreateUserRequest {
name: string;
email: string;
}
// API Base URL
const API_BASE_URL = 'http://localhost:8001/api/v1';
// Query Keys
export const userKeys = {
all: ['users'] as const,
lists: () => [...userKeys.all, 'list'] as const,
list: (filters?: any) => [...userKeys.lists(), filters] as const,
details: () => [...userKeys.all, 'detail'] as const,
detail: (id: string) => [...userKeys.details(), id] as const,
};
// API Functions
async function getUsers(): Promise<User[]> {
const response = await fetch(`${API_BASE_URL}/users`);
if (!response.ok) throw new Error('Failed to fetch users');
return response.json();
}
async function getUserById(id: string): Promise<User> {
const response = await fetch(`${API_BASE_URL}/users/${id}`);
if (!response.ok) throw new Error('Failed to fetch user');
return response.json();
}
async function createUser(data: CreateUserRequest): Promise<User> {
const response = await fetch(`${API_BASE_URL}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!response.ok) throw new Error('Failed to create user');
return response.json();
}
async function deleteUser(id: string): Promise<void> {
const response = await fetch(`${API_BASE_URL}/users/${id}`, {
method: 'DELETE',
});
if (!response.ok) throw new Error('Failed to delete user');
}
// React Query Hooks
export function useUsers() {
return useQuery({
queryKey: userKeys.lists(),
queryFn: getUsers,
});
}
export function useUser(id: string) {
return useQuery({
queryKey: userKeys.detail(id),
queryFn: () => getUserById(id),
enabled: !!id,
});
}
export function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: userKeys.lists() });
},
});
}
export function useDeleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
});
}
Use cases
React application integration
# Generate hooks
apicentric simulator generate-query --file services/api.yaml --output src/hooks/useApi.ts
// components/UserList.tsx
import { useUsers, useCreateUser } from '../hooks/useApi';
export function UserList() {
const { data: users, isLoading, error } = useUsers();
const createUser = useCreateUser();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
const handleCreate = async () => {
await createUser.mutateAsync({
name: 'John Doe',
email: '[email protected]',
});
};
return (
<div>
<button onClick={handleCreate}>Create User</button>
<ul>
{users?.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
Next.js integration
# Generate hooks for Next.js app
apicentric simulator generate-query --file services/api.yaml --output src/lib/api-hooks.ts
// app/users/page.tsx
'use client';
import { useUsers } from '@/lib/api-hooks';
export default function UsersPage() {
const { data, isLoading } = useUsers();
return (
<div>
{isLoading ? 'Loading...' : data?.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Optimistic updates
// Using generated hooks with optimistic updates
import { useUser, useUpdateUser } from './hooks/useApi';
function UserProfile({ userId }: { userId: string }) {
const { data: user } = useUser(userId);
const updateUser = useUpdateUser();
const handleUpdate = (name: string) => {
updateUser.mutate(
{ id: userId, name },
{
onMutate: async (newData) => {
// Optimistic update
await queryClient.cancelQueries({ queryKey: userKeys.detail(userId) });
const previous = queryClient.getQueryData(userKeys.detail(userId));
queryClient.setQueryData(userKeys.detail(userId), newData);
return { previous };
},
onError: (err, newData, context) => {
// Rollback on error
queryClient.setQueryData(userKeys.detail(userId), context?.previous);
},
}
);
};
return <div>{user?.name}</div>;
}
Automated generation in build
// package.json
{
"scripts": {
"generate:hooks": "apicentric simulator generate-query --file services/api.yaml --output src/hooks/api.ts",
"prebuild": "npm run generate:hooks",
"build": "vite build"
}
}
React Query setup
To use the generated hooks, set up React Query in your app:
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000, // 1 minute
retry: 1,
},
},
});
export function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app components */}
</QueryClientProvider>
);
}
Generated hooks automatically include cache invalidation, type safety, and follow React Query best practices. They work seamlessly with the simulator for local development and can be configured to point to production APIs.
Best practices
- Generate during build - Add to build scripts to keep hooks in sync
- Customize base URL - Update API_BASE_URL for different environments
- Add error handling - Extend generated hooks with custom error handling
- Use query keys - Leverage exported query keys for cache management
- TypeScript strict mode - Enable strict mode for maximum type safety
Configuration
Custom base URL
Modify the generated file to use environment variables:
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8001/api/v1';
Custom fetch options
Add authentication headers:
function fetchWithAuth(url: string, options?: RequestInit) {
return fetch(url, {
...options,
headers: {
...options?.headers,
'Authorization': `Bearer ${getToken()}`,
},
});
}
Troubleshooting
Failed to generate hooks
❌ Failed to generate hooks: missing endpoint definitions
Solution: Ensure your service definition includes endpoint definitions:
endpoints:
- path: /users
method: GET
# ...
TypeScript errors in generated code
Solution: Install React Query types:
npm install @tanstack/react-query
npm install -D @types/react
Hooks not updating cache
Solution: Ensure you’re using the QueryClientProvider and the generated query keys for cache invalidation.