feat: add support for the HTTP QUERY method (RFC 10008) - #2853
Conversation
👷 Deploy request for openapi-ts pending review.Visit the deploys page to approve it
|
🦋 Changeset detectedLatest commit: 4579dd9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
`pnpm exec playwright install --with-deps` has been hanging until the 6h GitHub Actions limit kills the job, so `test-e2e` has not completed on any PR since 2026-05-12. The hang is not in the system dependency install: apt finishes normally, then the job stalls right after the browser archive download reaches 100%, during extraction. The cause is a yauzl regression (thejoshwolfe/yauzl#168) where the `for await` over `openReadStream` never completes on Node 24.16.0+ and Node 26.x — see microsoft/playwright#40724, which was filed against Playwright 1.59.1 on Node 26, exactly this configuration. Playwright vendored the fix in 1.60.0; this repo has been pinned to 1.59.1 since 2026-04-01. The e2e job runs `node-version: latest`, which started resolving to Node 26 when 26.0.0 shipped on 2026-05-05 — the last green test-e2e run was 2026-05-05, and the first 6h hang was 2026-05-12. Renovate had already queued the 1.62.1 bump, but it is rate-limited in the dependency dashboard (openapi-ts#2173), and its devDependency automerge waits on a CI run that can no longer go green — so the update that fixes this is blocked by the problem it fixes. Also add `timeout-minutes` to the job: without it a future hang costs 6h of runner time per run, and in-progress job logs cannot be read via the API, which makes such a hang needlessly hard to diagnose. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
QUERY is a safe, idempotent HTTP method that carries a request body, filling the gap between GET (no body) and POST (neither safe nor idempotent). OpenAPI 3.2 recognises `query` as a Path Item verb, but openapi-typescript treated it as an unknown property and dropped it, so no types were generated and openapi-fetch had no way to call it. - openapi-typescript-helpers: add "query" to `HttpMethod` - openapi-typescript: emit a `query` operation for Path Items that declare one, and include it in path-param extraction and the paths enum. Path Items without a `query` operation are left untouched, so no existing generated output changes. - openapi-fetch: add `client.QUERY()` and `QUERY` on the path-based client Follow-up to openapi-ts#2844, which took the same approach but emitted `query?: never` on every Path Item of every document — churning ~4,400 lines of examples and fixtures, the concern its author raised for review. Emitting `query` only where it is declared keeps generated output byte-identical for documents that don't use it. Co-authored-by: Jonty Sewell <jonty@vallaton.co.uk> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
18fe8c5 to
4579dd9
Compare
|
Rebased onto #2854.
That means this PR temporarily contains #2854's commit as well — the Playwright bump, the |
Changes
Adds support for the HTTP
QUERYmethod (RFC 10008) toopenapi-typescriptandopenapi-fetch.QUERYis a safe, idempotent method that carries a request body, filling the gap betweenGET(no body) andPOST(neither safe nor idempotent). OpenAPI 3.2 recognisesqueryas a Path Item verb, and it survives YAML→JSON conversion fine, but the generator treated it as an unknown property and silently dropped it — so no types were emitted andopenapi-fetchhad no way to call such an endpoint.openapi-typescript-helpers— adds"query"toHttpMethod.openapi-typescript— emits aqueryoperation for the Path Items that declare one, and includesqueryin path-parameter extraction and the paths enum.openapi-fetch— addsclient.QUERY()andQUERYon the path-based client.This is a follow-up to #2844 (cc @jonty-comp, credited as co-author — this PR reuses their test schema and test cases), which has been open for a while. It takes the same approach with one deliberate difference, described below.
Generated output is unchanged for documents that don't use
queryThe concern @jonty-comp raised for review in #2844 was:
That is a real cost: adding
queryto the unconditional method list appendsquery?: never;to every Path Item of every document, which in #2844 meant ~4,400 changed lines acrossexamples/and fixtures, and would mean a churned diff in every downstream repo that checks in generated types.Since
querywas only introduced in OpenAPI 3.2, this PR emits it for the Path Items that declare it rather than for every Path Item:This is behaviourally equivalent for consumers —
PathsWithMethodtreats an absent key and an optionalneverkey identically — andquery?: neveris still emitted in the one case where it carries meaning (aqueryoperation excluded viaexcludeDeprecated).The result:
pnpm run update:examplesand regenerating everyopenapi-fetchtest schema produce zero diff. The only generated file added is the newquery.d.tsfixture.I'm happy to switch to unconditional emission if you'd rather keep all nine verbs symmetrical — it's a one-line change.
Idempotency
QUERYbeing safe and idempotent means sending a request twice must be equivalent to sending it once, so the client must not introduce per-request state of its own or consume the caller's input.coreFetchalready satisfies this; the PR adds tests that pin the behaviour:initobject can be reused across calls and is neither consumed nor mutated;Request, so the body is not read once and replayed.The request body is serialised with a
Content-Typeas RFC 10008 §2 requires.No retry or response-caching layer is added — that's out of scope for this PR, and
openapi-fetchdoesn't have one today.Out of scope
OpenAPI 3.2's
additionalOperations(arbitrary custom methods) is not addressed here.queryis a first-class method under the RFC and is worth landing on its own, as @jonty-comp noted.How to Review
packages/openapi-typescript/src/transform/path-item-object.tsholds the emission decision — that's the main thing worth a second opinion.pnpm run update:examplesinpackages/openapi-typescriptandpnpm run generate-typesinpackages/openapi-fetchshould both leave the tree clean.QUERYis not a forbidden method under the fetch spec, sonew Request(url, { method: "QUERY", body })works on Node 18+ and in browsers. Servers and intermediaries that don't forward the verb will of course still reject it; the docs note this.pnpm run lint,pnpm run test(780 tests), andpnpm run sizeall pass.Checklist
docs/updated (if necessary)pnpm run update:examplesrun (only applicable for openapi-typescript)