-
-
Notifications
You must be signed in to change notification settings - Fork 553
Labels
axiosAxios related issueAxios related issue
Description
Description
When using client: 'react-query' with httpClient: 'axios', developers need to inject a pre-configured axios instance (with interceptors, auth, base URL) at runtime. This is critical for:
- NPM package distribution: Library consumers need to inject their own axios config
- SSR: Each server request needs its own axios with request-specific headers
- Testing: Easy mock injection without complex module mocking
The axios client already supports this via PR #2851 (factory pattern). This proposal adds similar support for react-query using React Query’s native meta feature.
Related to #2851
Current behavior
Option 1: Global axios import → No configuration possible
Option 2: Custom mutator → Singleton created at module load, cannot be injected by library consumers or configured per-request (SSR)
Proposed behavior
New option httpClientInjection: 'reactQueryMeta' that reads axios from QueryClient.defaultOptions.meta:
Config
// orval.config.ts
{
output: {
client: 'react-query',
httpClient: 'axios',
httpClientInjection: 'reactQueryMeta', // NEW
}
}Generated code
// Resilient helpers - fallback to default axios if not configured
const getQueryAxiosInstance = (queryClient: QueryClient): AxiosInstance => {
try {
const instance = queryClient.getDefaultOptions()?.queries?.meta?.axiosInstance;
return (instance as AxiosInstance) ?? axios;
} catch {
return axios;
}
};
const getMutationAxiosInstance = (queryClient: QueryClient): AxiosInstance => {
try {
const instance = queryClient.getDefaultOptions()?.mutations?.meta?.axiosInstance;
return (instance as AxiosInstance) ?? axios;
} catch {
return axios;
}
};
// Generated hooks use the helpers
export const useListPets = (params?: ListPetsParams) => {
const queryClient = useQueryClient();
const axiosInstance = getQueryAxiosInstance(queryClient);
return useQuery({
queryKey: getListPetsQueryKey(params),
queryFn: ({ signal }) => axiosInstance.get('/pets', { params, signal }).then(r => r.data),
});
};
export const useCreatePets = () => {
const queryClient = useQueryClient();
const axiosInstance = getMutationAxiosInstance(queryClient);
return useMutation({
mutationFn: (data) => axiosInstance.post('/pets', data).then(r => r.data),
});
};Consumer usage
// Configure axios with interceptors
const apiClient = axios.create({ baseURL: process.env.API_URL });
apiClient.interceptors.request.use(addAuthHeader);
apiClient.interceptors.response.use(handleTokenRefresh);
// Inject via QueryClient meta
const queryClient = new QueryClient({
defaultOptions: {
queries: { meta: { axiosInstance: apiClient } },
mutations: { meta: { axiosInstance: apiClient } },
},
});
// Hooks automatically use the injected axios
const { data } = useListPets(); // Uses apiClient !Proposed solution
| File | Changes |
|---|---|
packages/core/types.ts |
Add httpClientInjection?: 'none' | 'reactQueryMeta' |
packages/query/src/* |
Generate helpers + useQueryClient() in hooks |
Benefits
- Zero memory overhead - No closures, reads from existing QueryClient
- SSR native - One QueryClient per request with its own axios
- Backwards compatible - Opt-in,
'none'is default - Resilient - Fallback to global axios if not configured or RQ v3
Compatibility
- ✅ React Query v3 (fallback), v4+, v5+
- ✅ All orval modes:
single,split,tags,tags-split ⚠️ Incompatible with custommutator(mutually exclusive)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
axiosAxios related issueAxios related issue