Skip to content

feat(server): add MethodOverrideHandlerPlugin - #1805

Merged
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/custom-method-query-params-2eabc1
Aug 8, 2026
Merged

feat(server): add MethodOverrideHandlerPlugin#1805
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/custom-method-query-params-2eabc1

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 7, 2026

Copy link
Copy Markdown
Member

Adds MethodOverrideHandlerPlugin to @orpc/server/plugins. A POST request carrying a method query parameter (e.g. POST /todos/1?method=DELETE) is routed and executed as that method, so HTML forms, which only support GET and POST, can invoke procedures routed as PUT, PATCH, or DELETE.

Behavior

  • The override only applies to POST requests; the param name (method) and allowed targets (PUT, PATCH, DELETE) are configurable.
  • The parameter is stripped from the URL before input decoding, so it never leaks into query-decoded input (including inputStructure: 'detailed').
  • Values outside the allowed list are silently ignored and the request proceeds as a regular POST.
  • GET and HEAD are excluded by default: they would switch input decoding from body to query and widen the CSRF surface.
  • Batch sub-requests are unaffected (after = ['~batch']).

Notes for reviewers

  • Works with both RPCHandler and OpenAPIHandler; it is most useful with the latter, where the method decides route matching.
  • Docs page warns the plugin is incompatible with SimpleCsrfProtectionHandlerPlugin, which blocks the navigate fetch mode real form submissions use.

Testing

  • Unit tests plus an RPCHandler integration test in packages/server, and OpenAPIHandler integration tests in tests/openapi (form-encoded POST hits a DELETE route with clean input, plain POST stays unmatched, no param leak into detailed query).
  • pnpm type:check, pnpm lint, and pnpm docs:validate pass.

Allow overriding the HTTP method of a POST request via a query parameter
(e.g. POST /todos/1?method=DELETE routed as DELETE), so HTML forms, which
only support GET and POST, can invoke PUT/PATCH/DELETE procedures. The
parameter is stripped before input decoding; disallowed values are
silently ignored.
@vercel

vercel Bot commented Aug 7, 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 7, 2026 2:22pm

@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/bun

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

@orpc/client

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

@orpc/cloudflare

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

@orpc/contract

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

@orpc/experimental-effect

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

@orpc/evlog

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

@orpc/hibernation

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

@orpc/json-schema

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

@orpc/nest

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

@orpc/next

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

@orpc/openapi

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

@orpc/opentelemetry

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

@orpc/pinia-colada

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

@orpc/pino

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

@orpc/publisher

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

@orpc/ratelimit

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

@orpc/server

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

@orpc/shared

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

@orpc/swr

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

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/zod

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

commit: 23dad39

@codecov

codecov Bot commented Aug 7, 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 7, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 25 untouched benchmarks


Comparing dinwwwh:claude/custom-method-query-params-2eabc1 (23dad39) with main (4757ab5)

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 found.

Reviewed changes

  • MethodOverrideHandlerPlugin — new @orpc/server/plugins export that rewrites a POST request's method (stripping the override query param) before routing; defaults to ?method= with PUT/PATCH/DELETE targets, both configurable. Placed after = ['~batch'] and prepended as a routing interceptor, mirroring RequestCompressionHandlerPlugin exactly, so only the original envelope is overridden — batch sub-requests (which route by RPC name) are unaffected.
  • Interceptor unit tests — cover override, case-insensitive matching, repeated params (last wins, all stripped), preservation of other params and the hash, disallowed values (including GET/HEAD/POST), custom param name and method set, plus an RPCHandler integration test.
  • OpenAPI integration tests — form-encoded POST routed to a DELETE operation with clean input; plain POST left unmatched; no override-param leak into detailed query input; disallowed value silently ignored.
  • Docs page — new /docs/plugins/method-override page with a setup example and an honest :::warning documenting the SimpleCsrfProtectionHandlerPlugin incompatibility.

I verified the interceptor composition: since each plugin prepends and intercept runs index 0 outermost, the after = ['~batch'] ordering places this interceptor outside the batch interceptor, exactly matching the stated intent of overriding the original request only. The parseStandardUrl/URLSearchParams handling is consistent with how the existing batch plugin consumes the same search fragment, and the test assertions are specific enough to fail if the described bugs were present.

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

Initialize before ~batch so each sub-request passes through the override
individually instead of only the outer batch request.

@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 critical issues — one verification gap inline.

Reviewed changes (delta since the prior pullfrog review of 8013866)

  • Batch-aware ordering flipMethodOverrideHandlerPlugin now declares before = ['~batch'] (was after), so the method override applies to each batch sub-request rather than the original batch envelope, with the doc comment updated to match ("override batch sub-request methods, not the original batch request").
  • No new tests in this delta for the changed batch behavior — the added unit, RPCHandler, and OpenAPI tests all exercise a single non-batch POST.

I verified the ordering semantics: before = ['~batch'] sorts the plugin before batch (init runs first, leaving batch outermost), so its interceptor sits inside batch and re-runs on each sub-request via the batch plugin's per-sub-request next(...) — matching how response-headers (before = ['~batch']) applies per sub-response, whereas request-compression uses after for original-only. The flip's stated intent is achieved; my one concern is that this changed behavior is unverified by a test.

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

Comment thread packages/server/src/plugins/method-override.ts
@dinwwwh
dinwwwh merged commit 0719979 into middleapi:main Aug 8, 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.

1 participant