Add support for the HTTP QUERY method#57973
Conversation
RFC 10008 defines QUERY as a safe and idempotent HTTP method that
conveys the query in the request content instead of the URL query
string. It is registered in the IANA HTTP Method Registry (safe: yes,
idempotent: yes) and is intended for queries too large or structured
for a query string: complex filters, search APIs, GraphQL, and
JSON-RPC style endpoints.
This registers QUERY as a known HTTP method in ActionDispatch::Request
and wires it through the framework:
* Add the RFC10008 constant to ActionDispatch::Request::HTTP_METHODS,
so QUERY requests no longer raise
ActionController::UnknownHttpMethod.
* Add ActionDispatch::Request#query?, mirroring the other verb
predicates (Rack::Request::Helpers does not define one for QUERY).
* Add a QUERY verb matcher to Journey (VerbMatchers::VERBS), so
`via: :query` routes match without the Unknown fallback.
* Add the `query` routing DSL method to
ActionDispatch::Routing::Mapper::HttpHelpers:
query "search", to: "search#index"
match "filter", to: "search#filter", via: :query
* Add the `query` request helper to integration tests:
query "/search", params: { filters: { q: "video" } }, as: :json
* Exempt QUERY requests from forgery protection, like GET and HEAD.
HTML forms cannot issue QUERY requests, and cross-origin QUERY
requests always require a CORS preflight (QUERY is not a
CORS-safelisted method), so the forgery surface is strictly smaller
than GET's. This exemption is kept in an isolated hunk so it is easy
to change if the exemption is not wanted.
Body parameter parsing needs no changes: parsing is keyed on
Content-Type rather than on the request method, so JSON and
form-encoded QUERY bodies already parse into params.
There are no behavior changes for existing applications: QUERY
requests previously raised ActionController::UnknownHttpMethod (405)
before reaching any application code.
Note that the application server must also accept the method. Puma
currently allows only the eight standard methods by default; QUERY can
be enabled with its `supported_http_methods` option.
References:
- RFC 10008: https://www.rfc-editor.org/rfc/rfc10008.html
- IANA HTTP Method Registry:
https://www.iana.org/assignments/http-methods/http-methods.xhtml
- Rails core forum proposal:
https://discuss.rubyonrails.org/t/proposal-support-for-the-http-query-method-rfc-10008/91255
|
Both rack/rack#2474 and puma/puma#3973 are related to this proposal. While those particular PRs might not be the ones to add support for Are there additional considerations to incorporate into the framework to support a fragmented and incremental roll-out of support for architectural dependencies (or other Rack web servers that are not |
|
Thanks for opening those, @seanpdoyle. This PR doesn't depend on either of them. Rails reads On incremental roll-out, each layer already degrades on its own:
The CHANGELOG entry documents the Puma opt-in for this reason. I can expand the routing guide with a short note on server support (Puma config, nginx mainline, CloudFront gap) and link the Rack/Puma PRs, either in this PR or as a follow-up. Two things I'd leave as deliberate follow-ups rather than v1 scope: the |
Summary
Registers the HTTP QUERY method (RFC 10008, June 2026, Proposed Standard) as a known HTTP method and wires it through Action Pack:
Motivation
QUERY is registered in the IANA HTTP Method Registry as safe and idempotent. It behaves like GET but carries the query in the request content, for queries too large or structured for a URL query string: complex filters, search endpoints, GraphQL, JSON-RPC.
Rails currently rejects the method before it reaches application code:
request_methodraisesActionController::UnknownHttpMethod(rendered as a 405),request.get?raises instead of returning false, andmatch ..., via: :querydraws a route that can never match.Proposed beforehand on the rails-core forum by Muhammet Dilmaç in Proposal: Support for the HTTP QUERY method (RFC 10008); this implements that proposal. Node.js core parses QUERY since 21.7.2, nginx supports it in recent mainline, and Spring has an open PR (spring-projects/spring-framework#34993).
Detail
ActionDispatch::Request:RFC10008constant appended toHTTP_METHODS, plus aquery?predicate (Rack::Request::Helpersdoes not define one).QUERYadded toVerbMatchers::VERBS.queryverb helper alongsideget/post/patch/put/delete.queryrequest helper. NoActionController::TestCasewrapper, mirroringoptions;process(:index, method: "QUERY")works there.Body parameter parsing needs no changes: parsing is keyed on Content-Type rather than the request method, so JSON and form-encoded QUERY bodies already parse into
params.No behavior changes for existing applications: QUERY requests previously raised before reaching any application code, so no framework default is needed.
Out of scope here: the
Accept-Queryresponse header, content-based cache keys for QUERY responses (RFC 10008 §2.7),resourcesintegration, method override, and aRack::Request#query?upstream addition.Note on servers: Puma only allows the eight standard methods by default and answers QUERY with a 501 unless its
supported_http_methodsoption is extended. That is a deployment concern outside Rails; this change makes Rails ready for the method without changing any server behavior.Checklist
[Fix #issue-number]