-
-
Notifications
You must be signed in to change notification settings - Fork 962
Using filter in query parameters breaks pagination #7888
Description
API Platform version(s) affected: at least 4.2 and 4.3
Description
When using filters via a nested filter[...] query parameter like:
http://<domain>/api/endpoint?filter[custom]=true
the default pagination parameters stop working as expected:
- page
- itemsPerPage
- pagination
After investigation, it appears that API Platform then expects pagination parameters to also be nested under filter, e.g.:
http://<domain>/api/endpoint?filter[custom]=true&filter[pagination]=false
If no filter[...] parameter is used, pagination works as documented:
http://<domain>/api/endpoint?page=2&itemsPerPage=10
Additionally, the pagination links returned in the response suggest that pagination parameters are still expected at the top level:
"links": {
"self": "/api/endpoint?filter[custom]=true&reload=true&page=1",
"first": "/api/endpoint?filter[custom]=true&reload=true&page=1",
"last": "/api/endpoint?filter[custom]=true&reload=true&page=7",
"next": "/api/endpoint?filter[custom]=true&reload=true&page=2"
}
This creates an inconsistency between how the API expects parameters and how it advertises them.
Possible Solution
Pagination handling should be independent of how filters are structured. Ideally, pagination parameters (page, itemsPerPage, pagination) should always be accepted at the top level, regardless of whether filters are passed as:
- flat query parameters (
?custom=true), or - nested (
?filter[custom]=true)
This would make the behavior more predictable and avoid coupling pagination parsing to filter structure.
Additional Context
The root cause appears to be how $context['filters'] is populated.
When using flat query parameters, pagination values (page, itemsPerPage) are present in $context['filters'] and correctly processed by ApiPlatform\State\Pagination\Pagination.
When using filter[...], only the nested filter values are included in $context['filters'], while pagination parameters remain outside and are therefore ignored by the pagination logic.
This leads to pagination not being applied unless it is also nested under filter[...].
Another source of confusion is the expectation based on the JSON:API specification:
https://jsonapi.org/format/#fetching-pagination
https://jsonapi.org/format/#fetching-filtering
https://jsonapi.org/format/#query-parameters-families
According to the JSON:API spec, query parameter families like filter[...] and page[...] are meant to coexist. Coming from that background, it is natural to structure requests like:
?filter[custom]=true&page[number]=2&page[size]=10
However, API Platform does not follow this convention and instead mixes pagination parameters into the same namespace (filters) internally. This mismatch leads to unexpected behavior when trying to combine structured filtering with pagination.
Clarifying this behavior in the documentation—or aligning parameter handling more closely with JSON:API conventions—would help avoid confusion.
Even more desireable would be to support the JSON:API spec for filtering and pagination when jsonapi is used as content type.
I would try to provide a solution, but I was lost when searching for where the significant portion of the $context variable population is happening.