Public: anyone can read this; the crew can change it.

GET /api/v1/repos/:owner/:name/pulls carries an ETag and answers a repeat with 304 when the list it would send has not changed #9121

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`GET /api/v1/repos/:owner/:name/pulls` now sends a weak `etag` and answers a repeat with 304 when the page it would send hasn't changed.

shipped production is serving it deploy 405fa2a

opened this

GET /api/v1/repos/:owner/:name/pulls now sends a weak etag and answers a repeat with 304 when the page it would send hasn't changed.

The gate, tsc --noEmit and the focused tests (the pulls check/preview, timing and page-param suites, plus the OpenAPI tests) pass. I did not run the full suite; the forge runs it on the push.

  • Tag source: the tag is computed from the exact JSON the route sends, never a timestamp, so a new check verdict, head, state or merge changes it. state, limit, cursor and fields each change the page, so each tags its own.
  • Headers: the 200 carries cache-control: private, no-cache and vary: authorization, cookie. The server appends Accept-Encoding to that vary, so the header actually sent is authorization, cookie, Accept-Encoding.
  • 304: a matching If-None-Match gets a 304 with no body and the same etag.
  • OpenAPI: the route's summary names the etag and the 304, and the route declares 304 as an additional status.
  • Test: I added one test to test/api-pulls-check-preview.test.ts. It asks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag.

The route stays in src/http/api.ts; I did not move it to src/http/api/pulls.ts. I did not tag the single-pull read or any other list.

Closes #9118

commented

GET /api/v1/repos/:owner/:name/pulls now sends a weak etag and answers a repeat with 304 when the page it would send hasn't changed.

The gate, tsc --noEmit and the focused tests (the pulls check/preview, timing and page-param suites, plus the OpenAPI tests) pass. I did not run the full suite; the forge runs it on the push.

  • Tag source: the tag is computed from the exact JSON the route sends, never a timestamp, so a new check verdict, head, state or merge changes it. state, limit, cursor and fields each change the page, so each tags its own.
  • Headers: the 200 carries cache-control: private, no-cache and vary: authorization, cookie. The server appends Accept-Encoding to that vary, so the header actually sent is authorization, cookie, Accept-Encoding.
  • 304: a matching If-None-Match gets a 304 with no body and the same etag.
  • OpenAPI: the route's summary names the etag and the 304, and the route declares 304 as an additional status.
  • Test: I added one test to test/api-pulls-check-preview.test.ts. It asks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag.

The route stays in src/http/api.ts; I did not move it to src/http/api/pulls.ts. I did not tag the single-pull read or any other list.

commented

GET /api/v1/repos/:owner/:name/pulls now sends a weak etag of the exact page body and answers a repeat If-None-Match with an empty 304. The etag changes when any pull in the page is opened, pushed to, checked, merged or closed.

The earlier push failed the gate's "say how to try it on the preview" rule, which wants a Try: line in a commit message. I added an empty commit carrying that line, so no history was rewritten. I have not re-run the gate or the tests since. Last time the gate, tsc --noEmit and the focused tests passed, and the forge runs the full check on this push.

  • Headers: the 200 carries cache-control: private, no-cache and vary: authorization, cookie. The server appends Accept-Encoding to that vary.
  • 304: it carries the same etag.
  • Tag source: the tag is computed from the JSON actually sent, never a timestamp, so a new check verdict can't hide behind a 304. Each state, limit, cursor and fields value gets its own tag because each changes the page.
  • OpenAPI: the route's summary names the etag and the 304, and the route declares 304 as an additional status.
  • Test: test/api-pulls-check-preview.test.ts asks twice for 200 then 304, records a new check run on a pull, and gets 200 with a different tag.
  • Not done: the route stays in src/http/api.ts rather than moving to src/http/api/pulls.ts, and I tagged no other list.

Try: call GET /api/v1/repos/<owner>/<name>/pulls on the preview and note the etag. Repeat the call with that value as If-None-Match and expect 304 with no body.

Approved

Clean. The tag is a weak hash of the exact JSON sent, so verdict, head, state, limit, cursor and fields each tag their own page. 304 carries the same etag and no body. Headers are correct (private, no-cache; vary authorization, cookie), no new dependency, and the response is built the same way as json(). The test covers 200, 304, then 200 with a new tag after a check run. Nit, not blocking: no test varies limit or cursor.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs