Hydra data provider ignores hydra:view pagination links, hardcodes page/itemsPerPage
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 64/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- react, typescript
Research direction
Start in src/hydra/dataProvider.ts at convertReactAdminRequestToHydraRequest and the response handling around lines 602-631. Trace how GET_LIST pagination requests and hydra:view links are processed; done means initial requests avoid forced pagination where appropriate, subsequent navigation follows hydra:next and hydra:previous, and cursor responses return pageInfo instead of total.
Written by the indexing model from the issue text.
Description
Description
The Hydra data provider hardcodes page and itemsPerPage query parameters on every GET_LIST request, ignoring the cursor-based pagination links (hydra:next, hydra:previous) returned in hydra:view.
This makes it impossible to use cursor-based (keyset) pagination — a common pattern for APIs that avoid offset-based pagination for performance and consistency reasons.
Current behavior
In convertReactAdminRequestToHydraRequest (dataProvider.ts#L413-L414):
if (page) url.searchParams.set('page', page.toString());
if (perPage) url.searchParams.set('itemsPerPage', perPage.toString());
These params are always appended to the request URL, regardless of what the server's hydra:view links specify.
On the response side (dataProvider.ts#L602-L631), when hydra:totalItems is present, the provider returns { data, total } and never reads hydra:view. The hydra:view / pageInfo path is only reached when totalItems is absent — but even then, subsequent requests still send page=N instead of following the cursor URLs from hydra:next / hydra:previous.
Expected behavior
When a collection response includes hydra:view with hydra:next / hydra:previous links, the data provider should use those URLs for navigation instead of constructing page=N&itemsPerPage=X params. This is how Hydra's PartialCollectionView is designed to work — the server tells the client how to navigate.
Specifically:
- For the first page, the provider should request the collection URL (optionally with
itemsPerPage/pageSizeif the server supports it) - For subsequent pages, the provider should follow
hydra:next/hydra:previousURLs from the response'shydra:view - When
hydra:viewis present withouthydra:last, the provider should returnpageInfo(nottotal) so react-admin uses next/prev navigation
Workaround
We currently bypass base.getList entirely in our data provider wrapper — we fetch the collection URL ourselves, track hydra:next/hydra:previous URLs from responses in a cache, and return pageInfo instead of total:
getList: async (resource, params) => {
const page = params.pagination?.page ?? 1;
const perPage = params.pagination?.perPage ?? 25;
const cached = cursorCache.get(cursorKey(resource, params));
let url;
if (page > 1 && cached?.page < page && cached?.nextUrl) {
url = new URL(cached.nextUrl, window.location.origin);
} else if (page > 1 && cached?.page > page && cached?.previousUrl) {
url = new URL(cached.previousUrl, window.location.origin);
} else {
url = new URL(`/api/${resource}`, window.location.origin);
url.searchParams.set("pageSize", String(perPage));
}
const response = await fetch(url.toString(), {
headers: { Accept: "application/ld+json" },
credentials: "include",
});
const json = await response.json();
const view = json["hydra:view"] ?? null;
cursorCache.set(key, {
nextUrl: view?.["hydra:next"] ?? null,
previousUrl: view?.["hydra:previous"] ?? null,
page,
});
return {
data: json["hydra:member"].map(normalize),
pageInfo: {
hasNextPage: !!view?.["hydra:next"],
hasPreviousPage: !!view?.["hydra:previous"],
},
};
}
This works but defeats the purpose of using the Hydra data provider in the first place.
Versions
@api-platform/admin: 4.2.4react-admin: 5.6.1
- Dominant language
- TypeScript
- Stars
- 516
- Forks
- 134
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from api-platform/admin
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
api-platform/admin#616 · 1 comment ·
-
Difficulty 4/5 3-5 days Newbie friendliness 50/100
api-platform/admin#659 · 1 reaction ·
-
Difficulty 3/5 1-2 days Newbie friendliness 35/100
api-platform/admin#631 · 6 comments ·
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
api-platform/admin#626 · 1 comment · 1 reaction ·
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
api-platform/admin#615 · 4 comments · 2 reactions ·
All issues in api-platform/admin
Similar issues
-
clawsweeper:linked-pr-open clawsweeper:no-new-fix-pr clawsweeper:source-repro impact:message-loss issue-rating: 🦞 diamond lobster maturity:stable P2
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#616 ·
-
ZCode 3.14.3 に対応する Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
supermomonga/zcode-acp#24 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
growthbook/growthbook#7100 ·
-
triage
Difficulty 1/5 1-3 hours Newbie friendliness 88/100