Repository navigation
/query optimization - #312
Conversation
|
Apologies for earlier comments being posted as general PR comments. Here are the specific inline suggestions:
These points target the code changes in this PR and should be applied accordingly. |
PR #295 added the sendMethodNotAllowed helper with 'POST,HEAD' on main. This PR removes the HEAD handler, so the Allow header must advertise only POST per RFC 9110 section 15.5.6. Merge main in to keep the branch conflict-free.
cubap
left a comment
There was a problem hiding this comment.
Review
Reviewed the full diff against issues #302, #304, and #96. The implementation is solid and spec-compliant:
- #302 (rel="next" paging): over-fetch
limit + 1and trim before serialization,setNextPageLinkhelper, OpenAPINextPageLinkcomponent, API.htmlpagedQueryrewritten to followrel="next"? all correct. Verified the alias path too:/v1/api/getByProperties.action?limit=2correctly links to/v1/api/query?limit=2&skip=2. - #304 (remove HEAD /query): handler, controller, export, OpenAPI op, contract test, and docs all removed consistently.
- #96 (HEAD artifacts): only
/queryhad an explicit HEAD handler;/sinceand/historyare GET routes where Express auto-answers HEAD, so nothing to remove there.
One issue found and fixed
After #295 merged (Allow headers on 405), main's routes/query.js advertises Allow: POST,HEAD. This PR removes the HEAD handler, so the merged result would advertise HEAD on a resource that no longer supports it ? a violation of RFC 9110 ?15.5.6, and it broke the route_wrappers test (rejects unsupported methods for /query).
I pushed a fix (commit 0d055df) that merges main into the branch and changes the 405 fallback to rest.sendMethodNotAllowed(res, '...', 'POST'). Full test suite now passes (132/132).
Minor note (no action needed)
db-controller.js.backup is a tracked stale backup that still contains queryHeadRequest ? pre-existing, not part of the build.
|
@thehabes ? I've pushed the suggested changes to |
Summary
Resolves #302.
POST /queryresponses carry an RFC 8288Link: <…>; rel="next"while another page exists, and omit it on the final page, so clients stop guessing from record counts.Resolves #304.
HEAD /queryis removed. It now answers405through the route's existing.all()fallback, like every otherPOSTroute.Resolves #96. The
/queryHEAD artifact is gone. HEAD on/since/:_idand/history/:_idis unchanged, because those areGETroutes where Express answers HEAD from theGEThandler.What changed
rel="next"on/query/queryover-fetches one record (limit + 1) to learn whether another page exists. The extra record is trimmed before serialization and never served.That is the response to
?limit=3&skip=6. The rules:setNextPageLink(req, res, { limit, skip, hasNext })helper incontrollers/utils.jscallsres.append, so the JSON-LD context link survives.RERUM_PREFIXorigin, never the request host. Without a usableRERUM_PREFIXthe link is path-only. The path is the route that was paged, so the legacygetByProperties.actionalias links to/v1/api/query.limit(after clamping) andskip + limit.next. Nofirst,prev, orlast.skipmaximum. Following it is answered with thelimitandskipsilently guess at invalid input, and an over-maximumskipreturns the same page forever #301400that names the maximum, so a walk too deep to finish ends loudly instead of looking complete.HEAD /queryremovedroutes/query.js:.head(controller.queryHeadRequest)is dropped.controllers/history.jsanddb-controller.js:queryHeadRequest, its export, and thegetPaginationimport only it used are deleted.routes/__tests__/route_wrappers.test.js: every route in the 405 table without aGEThandler is asserted to have noHEADhandler of its own, so adding one to a route that has noGETfails a test.Contract and documentation
openapi/contracts/core-provider.openapi.yaml: aNextPageLinkheader component is referenced asLinkon the/api/query200, and thehead:operation under/api/queryis removed along with its entry in__tests__/core_provider_contract.test.js.public/API.html: the Custom Query text points paged clients atrel="next".pagedQueryis rewritten to followrel="next"until it is gone, re-sending the same body, and to warn when anextpast theskipmaximum is answered with the400. A new "Followingrel="next"" section documents the link. The result-ordering text no longer mentionsHEAD.public/API.htmland thegetPaginationJSDoc no longer claim the pagination headers tell a truncated page from a final one.rel="next"does that now.Tests
routes/__tests__/query.test.js:nextis present and advancesskipwhile more records exist, absent on a final page of exactlylimitrecords, and coexists with the context link. The over-fetched record is never served at the maximumlimit.nextis still sent at theskipmaximum and following it is a400. A walk that follows onlynextreturns every record exactly once. The existing test that checks what reaches the database cursor now expects the over-fetchedlimit + 1. TheHEAD /querytests are removed.__tests__/utils.test.js:setNextPageLinkbuilds an absolute link on theRERUM_PREFIXorigin, a path-only link without it, nothing on the final page, and only ever appends.Verification
Read-only, against the local pm2 app reading the dev collection:
POST ?limit=3&skip=6nexttoskip=9POST ?limit=2over exactly 2 matchesPOST ?limit=1000&foo=barnextcarrieslimit=500, dropsfooPOST ?limit=500&skip=100000nexttoskip=100500POST ?limit=500&skip=100500400withPagination-Skip-Max: 100000POST /v1/api/getByProperties.action?limit=3nextto/v1/api/queryPOSTwith no matches200 [], context link onlyHEAD /v1/api/query405HEAD /v1/api/getByProperties.action405The published
pagedQueryexample, run against the same app over{"_id":{"$type":"string","$gte":"69e9"}}atlimit=500, read 2433 records in 5 pages with no duplicates and stopped whennextwas absent.Breaking
rel="next"is additive. Existing clients ignore the header and behave as they do now.HEAD /querynow answers405where it answered200or404. A client relying on it was already unreliable: HEAD cannot carry the filter body, and a bodilessHEADmatched every record.