-
-
Notifications
You must be signed in to change notification settings - Fork 559
Description
First of all
Thanks for your work on Orval! Any guidance or clarification on how to better handle these situations would be greatly appreciated.
Summary:
I'm using Orval to generate React Query hooks in my React application. My API returns pagination metadata in HTTP headers:
x-pagination-limit
x-pagination-offset
x-pagination-total-count
The response body is just an array of items.
Question 1: Accessing Headers
useInfiniteQuery requires getNextPageParam, but this function only receives the response body (lastPage), without access to headers.
Orval-generated hooks assume the fetcher returns only the parsed response body.
What I've tried
- I tried using a global mutator to return { data, headers }, but that changes the return type for all endpoints, breaking type safety and requiring major changes across the codebase.
- I tried using a global mutator to return AxiosResponse, that worked, i got access to axios response but the data type doesn't reflect it. I had to every time override the type.
There doesn't seem to be a clean way to access headers alongside the response data when using the generated hooks.
Is there a recommended way to handle this?
- Is it possible to configure Orval to expose both response data and headers in generated hooks?
- Can Orval support per-endpoint mutators or response transformations, so that only specific endpoints need to return { data, headers }?
- Or is there an existing pattern in Orval for working with header-based pagination, particularly with useInfiniteQuery?
Question 1: Pass page params
How to pass the pageParams generated by the getNextPageParam function to the payload? It doesn't inject by itself.?
Example of the scenario:
Response headers:
x-pagination-limit: 10
x-pagination-offset: 20
x-pagination-total-count: 100
Response body:
[
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
]Examples
Mutator used to return AxiosResponse
export function customInstance<T>(config: AxiosRequestConfig, options?: AxiosRequestConfig & {returnResponse?: boolean}): Promise<T>
export function customInstance<T>(config: AxiosRequestConfig, options?: AxiosRequestConfig & {returnResponse?: boolean}): Promise<AxiosResponse<T>> {
const accessToken = accessTokenManager.getToken();
const headers = new AxiosHeaders();
if (accessToken) {
headers.set('Authorization', `Bearer ${accessToken}`);
}
const source = Axios.CancelToken.source();
const promise = AXIOS_INSTANCE({
...config,
...options,
cancelToken: source.token,
headers: {
...config.headers,
...headers,
...options?.headers,
},
}).then((response) =>
// this is a workaround to return the response object instead of the data.
options?.returnResponse ? response : response.data);
// @ts-expect-error cancel is not defined
promise.cancel = () => {
source.cancel('Query was cancelled');
};
return promise;
};Use of seInfinity
const {
data: response, // type: ProductPackage[] but should be something like UseInfiniteQueryResult<ProductPackage[]>
isLoading,
isError,
error,
refetch,
fetchNextPage,
} = useGetAppProductPackagesInfinite(
selectedAccount?.appId || '',
{...payload},
{
request: {
returnResponse: true,
},
query: {
queryKey: getGetAppProductPackagesQueryKey(),
initialPageParam: {
page: 1,
limit: 20,
offset: 0,
},
getNextPageParam: (lastPage) => {
console.log('lastPage', lastPage); // type: ProductPackage[] but should be AxiosResponse<ProductPackage[]>
// just a test
return {
page: 1,
limit: 20,
offset: 20,
};
},
},
},
);Environment
Orval version: 7.5.0
React Query: 5.49.2
React: 18.3.1
API design: Pagination metadata in HTTP headers