You should have an OpenApi specification and an orval config where you define the mode as react-query.
module.exports = {petstore: {output: {mode: 'tags-split',target: 'src/petstore.ts',schemas: 'src/model',client: 'react-query',mock: true,},input: {target: './petstore.yaml',},},};
Checkout the orval config reference to see all available options.
The react query model will generate an implementation file with one custom hook per path in your OpenApi Specification.
Like the following example from this swagger:
export const showPetById = (petId: string, version: number = 1) => {return axios.get<Pet>(`/v${version}/pets/${petId}`);};export const getShowPetByIdQueryKey = (petId: string, version: number = 1) => [`/v${version}/pets/${petId}`,];export const useShowPetById = <Error = unknown>(petId: string,version: number = 1,queryConfig?: UseQueryOptions<AsyncReturnType<typeof showPetById>, Error>,) => {const queryKey = getShowPetByIdQueryKey(petId, version);const query = useQuery<AsyncReturnType<typeof showPetById>, Error>(queryKey,() => showPetById(petId, version),{ enabled: !!(version && petId), ...queryConfig },);return {queryKey,...query,};};
With the following example orval will generate a useQuery and useInfinteQuery with a nextId queryparam. You can also override the config for each one with the config props.
module.exports = {petstore: {output: {...override: {query: {useQuery: true,useInfinite: true,useInfiniteQueryParam: 'nextId',config: {staleTime: 10000,},},},},...},};
If needed you can also override directly to an operation or a tag
module.exports = {petstore: {output: {...override: {operations: {listPets: {query: {...},}},},}...},};
You can add a mutator function to your config and setup a custom instance of your prefered HTTP client.
module.exports = {petstore: {output: {...override: {mutator: {path: './api/mutator/custom-instance.ts',name: 'customInstance',},},}...},};
// custom-instance.tsimport Axios, { AxiosRequestConfig } from 'axios';export const AXIOS_INSTANCE = Axios.create({ baseURL: '' });export const customInstance = <T>(config: AxiosRequestConfig): Promise<T> => {const source = Axios.CancelToken.source();const promise = AXIOS_INSTANCE({ ...config, cancelToken: source.token }).then(({ data }) => data,);// @ts-ignorepromise.cancel = () => {source.cancel('Query was cancelled by React Query');};return promise;};
You can add an interceptor to set automatically your url
axios.interceptors.request.use((config) => {return {...config,baseURL: '<BACKEND URL>',};});
Like for the backend url you should use an interceptor to set your header automatically.
You can use a context to add automatically an authorization for example.
const AuthProvider = ({ children, initialState = null }: AuthProviderProps) => {// it's a quick demo with useState but you can also have a more complexe state with a useReducerconst [token, setToken] = useState(initialState);useEffect(() => {const interceptorId = axios.interceptors.request.use((config) => {return {...config,headers: token? {...config.headers,Authorization: `Bearer ${token}`,}: config.headers,};});return () => {axios.interceptors.request.eject(interceptorId);};}, [token]);return (<AuthContext.Provider value={token}><AuthDispatchContext.Provider value={setToken}>{children}</AuthDispatchContext.Provider></AuthContext.Provider>);};
Checkout here the full example