Behavioral Fixes for limit and skip - #310
Conversation
Review: pagination fixes look good, two asks before mergeThe behavioral change is what #300 and #301 need: Two things I'd like addressed before merging:
Related: the test file should cover the exact vector list from #301. The implementation rejects them correctly, but Cross-link: CenterForDigitalHumanities/TinyNode#132 consumes these |
Response to PR review #310 (comment)
Response to PR review #310 (comment)
Summary
Resolves #301.
Resolves #300.
POST /queryandHEAD /querynow page over.sort({ _id: 1 }), so page boundaries no longer rest on natural order.Partially addresses #307.
mergeSearchResults()now ranks on__rerum.score, the field the branch pipelines actually write. The embedded-object_iddedup bug is not fixed here.What changed
?limit=1e3?limit=10abc?limit=250.7?limit=abc,?limit=0x10,?limit=?limit=0,?limit=-5?limit=100&limit=200?limit=200&limit=100?skip=1e3?skip=2.9?skip=abc,?skip=-5,?skip=?limit=1000?skip=150000Values are now validated as decimal integer strings before they are parsed, because
Number.parseIntguesses. A parameter supplied more than once arrives from Express as an Array, which has no single correct reading, so it is refused rather than resolved by position.The two maximums are deliberately not alike
An over-maximum
limitis clamped. A page size the server can honour in part is conventional to reduce, and rejecting it would be the more breaking choice.An over-maximum
skipis rejected. Clamping it served the page at the maximum on every request past it —skip=100000,skip=100100andskip=250000returned byte-identical bodies — so a client advancingskipand stopping on an empty page never terminated, and accumulated the same records on every pass. There is no honest reading of it, so it is refused with a message naming the configured maximum.Every paged response now reports what was applied
The reported
limitandskipare the values actually applied, which is what lets a client tell a truncated page from a genuine final one. Names are unprefixed to match the existingAnnotations-GatheredandCurrent-Overwritten-Versionheaders rather than introduce a new prefix.Access-Control-Expose-Headersis already*, so browser clients can read them with no CORS change.Breaking
Requests that return 200 today return 400. Land on dev first and give known client maintainers notice.
The
skiprejection is the part most likely to be hit by something real, which is the point of it.{"@type":"oa:Annotation"}still returns a document atskip=100000on production, so the boundary is reachable by live traffic.The published
pagedQueryexample inpublic/API.htmlwas the non-terminating shape, so it is rewritten: it advances by the page size the server reports applying rather than byresults.length, stops on a short page, and lets the boundary 400 end a walk that runs too deep.Out of scope
limitorskipat all today and no drift guard covers them. Left to The pagination contract is undocumented, misdocumented, and absent from the OpenAPI contract #305.rest.messengerappends "The body of your request was invalid… make sure it is valid JSON" to every 400, which reads oddly on a query-string error. Narrowing it means touching the shared error renderer for all 400s. The pagination messages are written to stand on their own; worth its own issue.HEAD /queryanswering an empty page with 404 (HEAD /queryanswers an empty page with 404 wherePOST /queryanswers200 []#304) is untouched. It is blocked on HEAD history - since - query #96, and the reading there is that the.head()handler should be removed from/queryrather than repaired — note that/since/:_idand/history/:_idare.get()routes where HEAD is valid and should stay.