Skip to content

Preserve the declared query parameters in every pagination link. - #14

Merged
gustavofreze merged 2 commits into
mainfrom
feat/preserve-link-parameters
Oct 15, 2026
Merged

gustavofreze merged 2 commits into
mainfrom
feat/preserve-link-parameters

Conversation

@gustavofreze

Copy link
Copy Markdown
Member

Summary

The links of a page (self, first, prev, next and last, in the body and in the Link header) were rebuilt
from filter, sort and page only. Any other query parameter that a route reads was lost in every link. Found in
schedule: GET /v1/eligible-waitlist-entries?slot_start_time=...&slot_end_time=...&page[size]=1 answered the first
page with the window, but links.next carried no window, so the second page fell back to the default order and came
back empty although the store held more records. On GET /v1/availability-overrides?from=...&to=... the loss made the
next page return records outside the window. The service worked around the first route by decoding the JSON the
library produced and rebuilding the response.

A schema now declares the names of the extra parameters its route uses:

Schema::create()
    ->filterable(field: 'client_identifier', operators: [Operator::EQUAL])
    ->preserving(parameters: ['slot_start_time', 'slot_end_time']);

Criteria::fromQuery reads the declared parameters from the request and repeats them in every link, between sort and
the pagination, in the order the request carried them. A declared parameter that did not come is left out, and an
undeclared one is never copied. Names and values are percent-encoded, and a nested value such as window[from] keeps its
brackets. A name that is empty, carries a bracket, or equals filter, sort or page raises
PreservedParameterIsInvalid when the schema declares it, and so does a value that is neither a string nor a nested
array of strings. The library reads the values from the request itself, so they never diverge from what the client
sent, and the consumer declares only names.

Public API: backward compatible. Schema::preserving, PreservedParameters and PreservedParameterIsInvalid are the
additions, and Links::from, Offset\Page::from, Offset\Slice::from, Cursor\Page::from and Cursor\Keyset::from
gain an optional ?PreservedParameters $preserved = null as the last argument, so the release is 2.7.0. Without a
declaration the links are the ones of 2.6.1.

Related issue

None.

Checklist

  • Tests added or updated. The links of offset, slice and cursor pages in the body and in the Link header, a
    declared parameter that did not come, an undeclared one, nested values, reserved characters in names and values, and
    the invalid names and values.
  • Documentation updated when applicable. README: how a schema declares the parameters its links preserve, with the
    window of from and to and of slot_start_time and slot_end_time as the example.
  • make review passes.
  • make tests passes. 440 tests, lines 100% (1072/1072), MSI 100% (803 of 803 killed).

@gustavofreze
gustavofreze merged commit f4dd1a4 into main Oct 15, 2026
5 checks passed
@gustavofreze
gustavofreze deleted the feat/preserve-link-parameters branch October 15, 2026 01:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant