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

GET /api/v1/repos/:owner/:name/labels carries an ETag and answers a repeat with 304 until a label or its open count changes #9170

Merged opened this

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

Merged

`GET /api/v1/repos/:owner/:name/labels` now carries a weak ETag and answers a repeat with 304 until a label or its open count changes.

shipped production is serving it deploy 84c60a0

opened this

GET /api/v1/repos/:owner/:name/labels now carries a weak ETag and answers a repeat with 304 until a label or its open count changes.

test/labels-etag.test.ts passes, tsc --noEmit is clean and scripts/gate.ts printed nothing. I also ran the labels-adjacent suites that exist (api-labels-update, repo-reads-timing, parity, openapi-oa-pull-hold), and they pass. I did not run the full suite or scripts/fast.ts; the forge runs the full check on push.

  • Headers: a 200 carries etag (from weakEtag over the rendered page), cache-control: private, no-cache and vary: authorization, cookie. A repeat holding the tag in If-None-Match gets a 304 with the same three headers and no body, plus the floor headers.
  • Body: the body is the same bytes as before. I tag what pageOf already renders, so the open counts the reader sees are inside the tag.
  • Sealed issues: a writer and a signed-out reader get different tags once a sealed issue makes their open counts differ, so a reader's tag never matches a writer's body.
  • Errors: a 404 or a bad page parameter returns the existing response unchanged, with no ETag.
  • Files: the change is in src/http/api/labels.ts (the GET handler is now async) and the new test file. src/http/api.ts is untouched.
  • Tests: they cover 200 then 304, the tag moving on add, rename, remove, labelling an issue, and closing and reopening it, the writer/reader split, and the 404 and bad-page cases. I did not run them against the old code to confirm they fail without the change.

I left out ETags on the label write routes (POST, PATCH, DELETE). Each page and limit combination gets its own tag, as the issues list does.

To try it:

curl -si -H "authorization: Bearer $T" $URL/api/v1/repos/o/n/labels

Then repeat with -H 'if-none-match: <etag>' to get a 304.

Closes #9164

commented

GET /api/v1/repos/:owner/:name/labels now carries a weak ETag and answers a repeat with 304 until a label or its open count changes.

test/labels-etag.test.ts passes, tsc --noEmit is clean and scripts/gate.ts printed nothing. I also ran the labels-adjacent suites that exist (api-labels-update, repo-reads-timing, parity, openapi-oa-pull-hold), and they pass. I did not run the full suite or scripts/fast.ts; the forge runs the full check on push.

  • Headers: a 200 carries etag (from weakEtag over the rendered page), cache-control: private, no-cache and vary: authorization, cookie. A repeat holding the tag in If-None-Match gets a 304 with the same three headers and no body, plus the floor headers.
  • Body: the body is the same bytes as before. I tag what pageOf already renders, so the open counts the reader sees are inside the tag.
  • Sealed issues: a writer and a signed-out reader get different tags once a sealed issue makes their open counts differ, so a reader's tag never matches a writer's body.
  • Errors: a 404 or a bad page parameter returns the existing response unchanged, with no ETag.
  • Files: the change is in src/http/api/labels.ts (the GET handler is now async) and the new test file. src/http/api.ts is untouched.
  • Tests: they cover 200 then 304, the tag moving on add, rename, remove, labelling an issue, and closing and reopening it, the writer/reader split, and the 404 and bad-page cases. I did not run them against the old code to confirm they fail without the change.

I left out ETags on the label write routes (POST, PATCH, DELETE). Each page and limit combination gets its own tag, as the issues list does.

To try it:

curl -si -H "authorization: Bearer $T" $URL/api/v1/repos/o/n/labels

Then repeat with -H 'if-none-match: <etag>' to get a 304.

commented

GET /api/v1/repos/:owner/:name/labels now carries a weak ETag and answers a repeat with a 304 until a label or its open count changes.

The check failed because no commit message had a Try: line. I added one in a new commit and pushed it. bun scripts/gate.ts now passes locally. I didn't re-run the tests, since the new commit is empty and the code is unchanged.

What changed

  • A 200 from the labels route carries an etag from weakEtag over the rendered page, plus cache-control: private, no-cache and vary: authorization, cookie. The body is the same bytes as before.
  • A repeat holding that tag in If-None-Match gets a 304 with the same headers, no body, and the security headers.
  • The tag moves when a label is added, renamed or removed. It also moves when an issue carrying the label opens or closes.
  • A writer and a signed-out reader get different tags once a sealed issue makes their open counts differ. A reader never gets a 304 from a writer's tag.
  • A 404 or a bad page parameter returns the existing response with no ETag.
  • The change is in src/http/api/labels.ts and test/labels-etag.test.ts. src/http/api.ts is untouched.

Not done: the label write routes (POST, PATCH, DELETE) carry no ETag. Each page and limit combination gets its own tag, as the issues list does.

Try: GET /api/v1/repos/<owner>/<name>/labels on the preview. Then repeat it with If-None-Match set to the etag it returned, and expect a 304.

Approved

Clean. Mirrors the issues-list ETag pattern, reuses weakEtag/holds, tag is over the rendered page so per-reader open counts are inside it, 404/bad-page return early without a tag. Tests cover each behaviour. No security, dependency or docs concerns.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs