Skip to content

feat: add support for the HTTP QUERY method (RFC 10008) - #2853

Open
SteveGT96 wants to merge 2 commits into
openapi-ts:mainfrom
SteveGT96:feat/http-query-method
Open

feat: add support for the HTTP QUERY method (RFC 10008)#2853
SteveGT96 wants to merge 2 commits into
openapi-ts:mainfrom
SteveGT96:feat/http-query-method

Conversation

@SteveGT96

Copy link
Copy Markdown

Changes

Adds support for the HTTP QUERY method (RFC 10008) to openapi-typescript and openapi-fetch.

QUERY is a safe, idempotent 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, 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 and openapi-fetch had no way to call such an endpoint.

  • openapi-typescript-helpers — adds "query" to HttpMethod.
  • openapi-typescript — emits a query operation for the Path Items that declare one, and includes query in path-parameter extraction and the paths enum.
  • openapi-fetch — adds client.QUERY() and QUERY on 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 query

The concern @jonty-comp raised for review in #2844 was:

My principal concern in adding this feature is that all output types will be modified, even if they do not make use of query anywhere — which could confuse downstream consumers when all their fixtures suddenly change.

That is a real cost: adding query to the unconditional method list appends query?: never; to every Path Item of every document, which in #2844 meant ~4,400 changed lines across examples/ and fixtures, and would mean a churned diff in every downstream repo that checks in generated types.

Since query was only introduced in OpenAPI 3.2, this PR emits it for the Path Items that declare it rather than for every Path Item:

const methods: readonly Method[] = "query" in pathItem ? METHODS : ALWAYS_EMITTED_METHODS;

This is behaviourally equivalent for consumers — PathsWithMethod treats an absent key and an optional never key identically — and query?: never is still emitted in the one case where it carries meaning (a query operation excluded via excludeDeprecated).

The result: pnpm run update:examples and regenerating every openapi-fetch test schema produce zero diff. The only generated file added is the new query.d.ts fixture.

I'm happy to switch to unconditional emission if you'd rather keep all nine verbs symmetrical — it's a one-line change.

Idempotency

QUERY being 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. coreFetch already satisfies this; the PR adds tests that pin the behaviour:

  • repeated identical calls produce byte-identical requests (method, URL, headers, body);
  • the caller's init object can be reused across calls and is neither consumed nor mutated;
  • each call builds its own Request, so the body is not read once and replayed.

The request body is serialised with a Content-Type as RFC 10008 §2 requires.

No retry or response-caching layer is added — that's out of scope for this PR, and openapi-fetch doesn't have one today.

Out of scope

OpenAPI 3.2's additionalOperations (arbitrary custom methods) is not addressed here. query is 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.ts holds the emission decision — that's the main thing worth a second opinion.
  • To confirm the no-churn claim: pnpm run update:examples in packages/openapi-typescript and pnpm run generate-types in packages/openapi-fetch should both leave the tree clean.
  • Runtime support: QUERY is not a forbidden method under the fetch spec, so new 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), and pnpm run size all pass.

Checklist

  • Unit tests updated
  • docs/ updated (if necessary)
  • pnpm run update:examples run (only applicable for openapi-typescript)

@SteveGT96
SteveGT96 requested a review from a team as a code owner August 24, 2026 10:28
@netlify

netlify Bot commented Aug 24, 2026

Copy link
Copy Markdown

👷 Deploy request for openapi-ts pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 4579dd9

@changeset-bot

changeset-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4579dd9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
openapi-typescript-helpers Minor
openapi-typescript Minor
openapi-fetch Minor
openapi-react-query Major

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>
@SteveGT96
SteveGT96 force-pushed the feat/http-query-method branch from 18fe8c5 to 4579dd9 Compare August 24, 2026 11:32
@SteveGT96

Copy link
Copy Markdown
Author

Rebased onto #2854.

test-e2e currently hangs on every PR in this repo until the 6h runner limit kills it, so this PR could not show a complete CI run. #2854 diagnoses and fixes that (a yauzl regression on Node 26 in Playwright < 1.60.0). I have rebased this branch on top of it so the e2e job can actually finish here.

That means this PR temporarily contains #2854's commit as well — the Playwright bump, the timeout-minutes guard and the lockfile change. Once #2854 is merged I will rebase onto main and that commit will drop out, leaving only the QUERY changes. If you would rather review this against main as-is, say so and I will drop the rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant