Skip to content

feat(rpc,openapi): add end-to-end HTTP QUERY support - #1844

Merged
dinwwwh merged 16 commits into
middleapi:mainfrom
aldotestino:feature/query-requests
Aug 12, 2026
Merged

feat(rpc,openapi): add end-to-end HTTP QUERY support#1844
dinwwwh merged 16 commits into
middleapi:mainfrom
aldotestino:feature/query-requests

Conversation

@aldotestino

@aldotestino aldotestino commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #1841

This PR adds end-to-end support for the HTTP QUERY method across oRPC RPC links, OpenAPI routes, request deduplication, batching, CORS, and tests.

QUERY is defined by RFC 10008 as a safe and idempotent method that carries query input in the request body. It fills the gap between GET, which is safe but puts input in the URL, and POST, which supports a body but does not communicate safe or idempotent semantics.

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview Aug 12, 2026 8:02am

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

This PR introduces a security boundary bypass: a malicious client can tunnel an unsafe POST sub-request through a safe outer QUERY batch, and the server executes it. The QUERY batch path does not enforce the "safe batch only carries safe sub-requests" rule that the GET path already enforces and that this PR's docs claim.

Reviewed changes — thorough end-to-end HTTP QUERY (RFC 10008) support across client, server, and openapi in 33 files:

  • RPC transportRPCLink/RPCLinkCodec accept method: 'QUERY' and fallbackMethod: 'QUERY' (body-encoded GET fallback); RPC handler keeps QUERY out of default allowMethods (opt-in), and RPC_DEFAULT_ALLOW_METHODS is unchanged.
  • OpenAPIopenapi() meta accepts method: 'QUERY'; the generator emits a query Path Item and hard-errors unless base.openapi is '3.2.0'; OpenAPIDocument narrows openapi to add '3.2.0' and adds OpenAPIPathItemObject.query.
  • Deduplication — default filter now covers both GET and QUERY.
  • Batching — client partitions GET/QUERY/unsafe into separate outer batches; server validates safe outer GET/QUERY batches contain only same-method sub-requests (see inline finding).
  • CORS — default Access-Control-Allow-Methods adds QUERY.
  • Docs + playground + e2e — routines, searchPlanets example, and a node-http QUERY batch round-trip test.

Despite the breadth, this is well-tested and clearly written; the batching security boundary is the one real issue. Everything else — codec fallback, OpenAPI 3.2 gating, dedupe default, CORS default, and the node-http/OpenAPI round trips — checked out against the implementation.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread packages/server/src/plugins/batch.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — single new commit (9f470f98 fix(server): validate body-encoded batch messages) addressing the prior security finding:

  • Closed the QUERY batch smuggling hole — the QUERY/body parse branch now applies the same isClientPeerSendMessage guard already used by the GET branch and the WebSocket/message-port/crossws handlers, so a kind: 'response' (or other non-request) message can no longer be executed as a POST sub-request under a safe outer QUERY batch.
  • Unified the safe-batch method check — the GET-only mismatch check was consolidated into one outer-method validation (GET/QUERY batches carry only same-method request sub-requests, else 400), preserving the prior GET behavior while extending it to QUERY.
  • Added regression coverage — a new test asserts a QUERY batch containing a { kind: 'response', method: 'POST', url: '/ping' } message returns 400 before any handler runs.

The bottleneck change is minimal, correct, and covered by a test that fails without it. I verified the supplementary guard matches how the other adapters validate inbound messages, and that the unified check does not disturb the streaming/buffered paths. All 73 affected tests (server batch, client batch, CORS, e2e batch) pass.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@dinwwwh

dinwwwh commented Aug 11, 2026

Copy link
Copy Markdown
Member

I don't think we need to document the QUERY method. We can just treat it like any other normal method. It shouldn't be used by default, and if someone chooses to use it, they should already understand what the QUERY method is.

@dinwwwh dinwwwh changed the title feat(client,server,openapi): add end-to-end HTTP QUERY support feat(rpc,openapi): add end-to-end HTTP QUERY support Aug 11, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No code issues in this delta — but it strips the QUERY documentation, leaving the shipped feature undocumented and one doc line now contradicting the code.

Reviewed changes — single commit (2a0ccdab docs: remove QUERY method guidance) since the prior Pullfrog review. It reverts the QUERY documentation added earlier in this PR across eight docs files (routing.mdx, specification.mdx, batch.mdx, cors.mdx, dedupe.mdx, handler.mdx, link.mdx, protocol.mdx). Net effect against main: the PR's docs delta is now empty.

ℹ️ Feature ships with no documentation while the PR advertises it

The code in this PR still implements end-to-end QUERY support (RPCLink/fallbackMethod, the OpenAPI 3.2 query Path Item and its hard '3.2.0' gate, method-partitioned batching, CORS default, dedupe default), but this commit removes every QUERY section the PR added. The PR body explicitly lists "Documentation" as a deliverable ("The documentation now covers: …"), so the diff now contradicts the description. This looks like either an accidental revert of the docs work or an intentional deferral to a separate PR. If it's intentional, updating the PR description avoids the mismatch; if not, the QUERY docs should be restored before merge — otherwise users get a substantial feature with no way to discover how to enable or reason about it.

ℹ️ dedupe.mdx reverts to a statement that contradicts the shipped behavior

The revert restores apps/content/docs/plugins/dedupe.mdx to "By default, the plugin deduplicates only GET requests." That is now false for this PR: DedupeLinkPlugin's default filter is ({ request }) => request.method === 'GET' || request.method === 'QUERY' (packages/client/src/plugins/dedupe.ts:51), so the default deduplicates GET and QUERY. A reader relying on the docs would be misled about whether their safe QUERY requests are collapsed. (This line can't be anchored inline because it no longer differs from main in the PR diff.)

Technical details
# Restore or explicitly defer QUERY documentation

## Affected sites
- apps/content/docs/openapi/routing.mdx — "QUERY Method" section removed
- apps/content/docs/openapi/specification.mdx — "QUERY Operations" section removed (incl. the `base.openapi: '3.2.0'` requirement)
- apps/content/docs/plugins/batch.mdx — "Request Methods" section removed
- apps/content/docs/plugins/cors.mdx — note that the default `allowMethods` includes QUERY removed
- apps/content/docs/plugins/dedupe.mdx — reverted to "only GET", contradicting code default (dedupe.ts:51)
- apps/content/docs/rpc/handler.mdx, rpc/link.mdx, rpc/protocol.mdx — QUERY guidance removed

## Required outcome
- A user of the shipped QUERY feature must be able to discover, configure, and understand its semantics from the docs — or the author must confirm the docs are intentionally deferred and align the PR description accordingly (and the dedupe default statement must not contradict the code).

## Open questions for the human
- Is the docs removal intentional (separate docs PR coming), or an accidental revert that should be restored before merge?

Pullfrog  | Fix it ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues in this delta — a clean upstream-main merge.

Reviewed changes — single commit (aebd399b Merge upstream main into feature/query-requests) since the prior Pullfrog review. It syncs main into the feature branch, bringing upstream's SimpleCsrfProtection Sec-Fetch-Site rework, a CORS origin/timingOrigin change (now string | undefined, reflected only when defined), and a batch sub-request-headers test. None of this is authored for the QUERY feature and none of it touches QUERY semantics.

I spot-checked the merged files to confirm the QUERY work survived intact: the CORS default still includes QUERY (cors.ts:83), the batch outer-method validation still covers GET/QUERY (batch.ts:175), and the codec method/fallbackMethod unions still accept QUERY (rpc-link-codec.ts:35,43). All 112 affected tests (dedupe, client + server batch, CORS, OpenAPI generator, e2e batch) pass on the merged tree.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1844

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1844

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1844

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1844

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1844

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1844

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1844

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1844

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@1844

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1844

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1844

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1844

@orpc/node

npm i https://pkg.pr.new/@orpc/node@1844

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1844

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1844

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@1844

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1844

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1844

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1844

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1844

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1844

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@1844

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1844

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1844

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1844

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1844

commit: f9a7913

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing aldotestino:feature/query-requests (f9a7913) with main (1d6dbe6)

Open in CodSpeed

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues in this delta — the QUERY feature remains intact and the code is clean.

Reviewed changes — since the prior Pullfrog review, four QUERY-authored commits plus a main sync landed on feature/query-requests:

  • Corrected the dedupe docs (2ac80f40) — dedupe.mdx now states the default dedupes GET and QUERY, matching dedupe.ts:51 and resolving the doc/code contradiction flagged earlier.
  • Restored OpenAPI QUERY docs + narrowed the document type (4110b782) — specification.mdx again documents the OpenAPI 3.2 QUERY requirement, and OpenAPIDocument now inlines the path-item query field (the intermediate OpenAPIPathItemObject/OpenAPIPathsObject exports are unreferenced anywhere, so removing them is safe).
  • Removed the Bun playground searchPlanets example (01bdcd46) — the playground generator was also reverted to the default OpenAPI 3.1.
  • Added a nest @Implement QUERY guard (3469719f) — a clear TypeError instead of the obscure MethodDecoratorMap[method] is not a function, since NestJS has no QUERY route decorator.
  • Merged more upstream main (beb04e70) — CSRF-rework and client batch fixes that are upstream-authored, not part of the QUERY feature.

I verified the nest guard against MethodDecoratorMap (no QUERY key), confirmed the inlined path-item type change with the updated types.test-d.ts assertion, and ran the affected tests (108 pass) plus pnpm type:check.

ℹ️ PR description is now out of sync with the code

The description's "Bun playground" section still claims the searchPlanets demo is present, was "verified through OpenAPIHandler with a real QUERY request", and that the playground "generates its reference document as OpenAPI 3.2.0". Commit 01bdcd46 removes that procedure and reverts the playground to the default 3.1. The feature and its tests stand on their own, so this is a description-vs-code mismatch rather than a functional issue — but the description should be updated (or the example restored) before this is presented as shipped.

Technical details
# Restore the playground example or update the PR description

## Affected sites
- playgrounds/bun/src/routers/planet.ts — `searchPlanets` (QUERY /planets/search) removed
- playgrounds/bun/src/routers/index.ts — `search: searchPlanets` removed
- playgrounds/bun/src/index.ts — `openapi: '3.2.0'` reverted to default 3.1
- PR description "Bun playground" / "Scalar API Reference" sections — still describe the example as delivered

## Required outcome
- Either keep the playground `searchPlanets` demo (and its OpenAPI 3.2.0 generation) and test, or update the PR description so readers are not told a delivered example exists when it does not.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end support for the HTTP QUERY method across oRPC’s client/server transport stack and OpenAPI integration, aligning batching, deduplication, CORS defaults, and tests/docs with RFC 10008 semantics (safe + idempotent, body-bearing).

Changes:

  • Add QUERY support to client plugins (batching + dedupe) and transport codecs/links, with corresponding test coverage.
  • Extend server-side batching validation and CORS defaults to include QUERY.
  • Add partial OpenAPI 3.2 typing/generation support for query operations, plus documentation updates and NestJS guardrails.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/batch/batch-plugin.test.ts Adds an e2e batch test asserting QUERY batching over node-http.
tests/batch/shared/client-server.ts Extends shared test helper options to allow selecting QUERY.
tests/batch/shared/client-server.node-http.ts Allows configuring link method; updates handler allowed methods (but currently misses GET).
tests/batch/shared/client-server.hono-fetch.ts Makes method configurable (default GET) and allows QUERY.
packages/server/src/plugins/cors.ts Adds QUERY to the default CORS Access-Control-Allow-Methods set.
packages/server/src/plugins/cors.test.ts Updates expected allow-methods string and adds an explicit allowMethods override test.
packages/server/src/plugins/batch.ts Tightens validation for body batches and enforces method-consistency for outer GET/QUERY batches.
packages/server/src/plugins/batch.test.ts Adds QUERY batch request helpers/tests and strengthens invalid-body assertions.
packages/openapi/src/types.ts Introduces an OpenAPIDocument type that supports OpenAPI 3.2 query operations in paths.
packages/openapi/src/types.test-d.ts Adds type tests to ensure query path items are supported under OpenAPI 3.2.
packages/openapi/src/openapi-generator.ts Rejects QUERY operations unless the base document is OpenAPI 3.2.0.
packages/openapi/src/openapi-generator.test.ts Adds tests for generating and rejecting QUERY operations depending on OpenAPI version.
packages/openapi/src/meta.ts Extends OpenAPI meta method union to include QUERY.
packages/openapi/src/adapters/fetch/openapi-link.test.ts Adds a test verifying QUERY OpenAPI requests carry input in the body.
packages/nest/src/implement.ts Throws if @Implement is used with QUERY since NestJS doesn’t support that method.
packages/nest/src/implement.test.ts Adds coverage for the NestJS QUERY rejection behavior.
packages/client/src/plugins/dedupe.ts Dedupe plugin defaults expanded to include QUERY requests.
packages/client/src/plugins/dedupe.test.ts Adds tests for deduping QUERY requests (same vs different bodies).
packages/client/src/plugins/batch.ts Splits batching into GET, QUERY, and unsafe (POST outer) batches.
packages/client/src/plugins/batch.test.ts Updates tests to assert distinct GET/QUERY/unsafe batch grouping.
packages/client/src/adapters/standard/rpc-link-codec.ts Extends method/fallback typing to allow QUERY.
packages/client/src/adapters/standard/rpc-link-codec.test.ts Adds a test for GET URL overflow fallback to QUERY.
packages/client/src/adapters/fetch/rpc-link.test.ts Adds a test asserting QUERY requests send body-encoded input.
packages/client/src/adapters/fetch/rpc-link.test-d.ts Adds type assertions around allowed QUERY usage and disallowed fallbacks.
apps/content/docs/plugins/dedupe.mdx Updates docs to reflect default dedupe for GET + QUERY.
apps/content/docs/plugins/cors.mdx Updates docs to include QUERY in the CORS allowMethods example.
apps/content/docs/openapi/specification.mdx Documents partial OpenAPI 3.2 support and the requirement for 3.2.0 when using QUERY.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/batch/__shared__/client-server.node-http.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@dinwwwh
dinwwwh merged commit 2bc387b into middleapi:main Aug 12, 2026
12 checks passed
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.

Support the HTTP QUERY method

4 participants