HTTP Gets a QUERY Method, and It Fits GraphQL Queries Very Well

Every GraphQL client eventually has to pick between two HTTP methods, and both come with a problem attached. GET is safe and cacheable, but it puts the whole document into the URL. POST carries the document in a body, but HTTP has to assume that every POST might change something, so caches and retry logic stay away from it. In June 2026 the IETF published RFC 10008, which defines a third option: QUERY, a method that carries a body like POST and is safe and idempotent like GET. That description also fits a GraphQL query operation very closely.
GET or POST: Pick Your Problem
A GraphQL query sent with GET goes into the query string:
GET /graphql?query=query%20MovieTitle%28%24id%3A%20ID%21%29%20%7B%20movie%28id%3A%20%24id%29%20%7B%20title%20%7D%20%7D&variables=%7B%22id%22%3A%221%22%7D HTTP/1.1
Host: api.example.com
Accept: application/graphql-response+json
That URL is cacheable by every browser, proxy and CDN on the way, which is the good part. The bad part starts with size. A real operation with a few fragments can run to several kilobytes, and RFC 9110 only recommends that software support URIs of at least 8000 octets. The variables also travel in the URL, and URLs end up in access logs, browser history and Referer headers. The Spring for GraphQL documentation warns about these risks before it lets you enable GET.
So POST became, in the words of the GraphQL over HTTP editor's notes, "the de facto standard". The body can be any size, and its contents stay out of the URL logs. The price is that HTTP defines POST as a method that may change state. A cache does not answer a POST with a stored response, and an HTTP client does not retry a failed POST on its own, because the first attempt might have changed something on the server. For a mutation, that caution is correct. For a query that only reads data, the same caution costs two useful features of HTTP: caching and automatic retries.
GraphQL developers have worked around this for years. Persisted documents replace the document with a short identifier, which makes GET URLs small enough to cache. They work well, and they need a build step and a registry of documents.
What RFC 10008 Defines
The abstract of RFC 10008 describes the method in one sentence:
A QUERY requests that the request target process the enclosed content in a safe and idempotent manner and then respond with the result of that processing.
The RFC compares the three methods in a table, shortened here:
GET | QUERY | POST | |
|---|---|---|---|
| Safe | Yes | Yes | Potentially not |
| Idempotent | Yes | Yes | Potentially not |
| Request body | No defined meaning | Expected | Expected |
| Cacheable | Yes | Yes | Only for later GET or HEAD requests |
Safe means the client does not ask for any change on the server. Idempotent means sending the same request twice has the same effect as sending it once, so a client or a proxy can repeat it after a dropped connection. Together with being cacheable, these properties let proxies and clients cache and repeat a GET without asking anyone. QUERY has all three.
The rest of the RFC covers what changes when a body becomes part of a safe request:
- A
Content-Typeis required. Section 2 says servers MUST fail aQUERYrequest without one, because the media type is part of what the query means. - The body is part of the cache key. Section 2.7 requires caches to include the request content in the key. Caches may normalize the content first, for example by ignoring formatting differences in a JSON body.
- A query can get its own URL. A server may answer with a
Locationheader that points at aGETURL for the same query, so a client can switch to cheapGETrequests for repeats. - Servers can advertise support. The new
Accept-Queryresponse header lists the media types a resource accepts in aQUERYbody. - Browsers send a preflight.
QUERYis not on the list of CORS-safelisted methods, so a cross-originQUERYfrom a browser always starts with anOPTIONSrequest.
A GraphQL Request over QUERY
A GraphQL request over QUERY looks like the POST request you already send, with a different method name. We ran it against a Spring Boot 4.2.0-M2 application with Spring for GraphQL 2.1.0-M1, which supports QUERY as an opt-in:
QUERY /graphql HTTP/1.1
Content-Type: application/json
Accept: application/graphql-response+json
{"query":"query MovieTitle($id: ID!) { movie(id: $id) { title } }","variables":{"id":"1"}}
HTTP/1.1 200
Content-Type: application/graphql-response+json
{"data":{"movie":{"title":"The Matrix"}}}
curl sends it with -X QUERY, and the JavaScript fetch function accepts method: "QUERY" the same way it accepts any other method name.
The safety promise has one consequence for GraphQL: a mutation over QUERY breaks it. The same rule already applies to GET in the GraphQL over HTTP draft, and Spring for GraphQL applies it to both methods. Here is a mutation sent with QUERY to the same application:
QUERY /graphql HTTP/1.1
Content-Type: application/json
Accept: application/graphql-response+json
{"query":"mutation RateMovie { rateMovie(id: \"1\", stars: 5) { title } }"}
HTTP/1.1 422
Content-Type: application/graphql-response+json
{"errors":[{"message":"Operation type 'MUTATION' is not allowed for this request","extensions":{"classification":"OperationNotSupported"}}]}
A mutation sent with GET gets 405 Method Not Allowed and an Allow header instead. The Spring documentation explains the difference: the endpoint does support the QUERY method, so 405 "would not be accurate", and the problem is the content of the request.
Turning It On in Spring
Spring Boot 4.2.0-M2 adds a property for the allowed methods (spring-boot #51732). The default is POST only:
spring.graphql.http.methods=POST,QUERY
The startup log confirms the change:
GraphQL endpoint HTTP [QUERY, POST] /graphql
Without Spring Boot, the transports documentation shows the same configuration on the handler and on the request predicate:
GraphQlHttpHandler httpHandler = GraphQlHttpHandler.builder(webGraphQlHandler)
.httpMethods(HttpMethod.QUERY, HttpMethod.POST)
.build();
RequestPredicate predicate = GraphQlRequestPredicates.graphQlHttp("/graphql",
Set.of(HttpMethod.QUERY, HttpMethod.POST));
Three things are worth knowing before you try it:
- Everything here is a pre-release.
HttpMethod.QUERYarrived in Spring Framework 7.1.0-M2, released on 24 September 2026 with Spring for GraphQL 2.1.0-M1 and Spring Boot 4.2.0-M2. We repeated the requests above on the release candidates of 22 October and got the same responses. The final releases are planned for 19 November. In the pull request that added it, Brian Clozel of the Spring team wrote that they would like to support it "in time for Spring Framework 7.1 in November". - Spring Security asks for a CSRF token. The Spring documentation points out that Spring Security's
CsrfFilterrequires a token forQUERY, becauseQUERYis missing from its list of safe methods. Check your CSRF rules before you move clients fromPOST. - One name was already taken. In the same pull request, he noted "the fact that
@QueryMappingalready exists in spring graphql". A proposal to add a@QueryMappingannotation for HTTPQUERYendpoints to Spring Framework was closed, so for now@QueryMappingstill means a GraphQL query.
We also tried the two discovery mechanisms from the RFC. Appendix A.2 of the RFC reads the supported methods from the Allow header of an OPTIONS response, and an OPTIONS request to /graphql returned 404. The responses did not include an Accept-Query header either. A GET request returned 405 with Allow: QUERY,POST, so the Allow header on that response still tells a client that the endpoint accepts QUERY.
Where the Rest of the Ecosystem Is
GraphQL over HTTP does not mention QUERY yet. The first edition's editor's notes list it as future work, and PR #411 by Martin Bonnin proposes the text. In its current form, servers SHOULD support QUERY, a mutation sent with QUERY MUST get a 422, and a note recommends QUERY over POST for query operations where possible. Spring's 422 from the example above already matches it. The working group's open questions in that pull request are about caching: whether the specification should recommend cache directives, how caches should normalize GraphQL documents, and what QUERY means for subscriptions, which are not cacheable.
Elsewhere, support is arriving one project at a time. In October 2026 these were all open:
- urql PR #3905,
QUERYrequests in the urql client - apollo-feature-requests #473, a request for
QUERYsupport across Apollo's tools - gqlgen #4295 and Strawberry #4632, server support in Go and Python
- Kubernetes Gateway API #5391, so that routing rules can match the method
- WHATWG HTML #12594,
QUERYas a form method
The author of the Spring Framework pull request keeps an ecosystem adoption tracker for the method across languages and products.
Should You Use It Yet?
For server-to-server GraphQL calls inside your own network, QUERY is worth trying as soon as your framework supports it. Retries become safe to automate, and the method name tells every proxy and log reader that the request only reads data.
For browsers and public APIs, POST remains the safe default for now. Every cross-origin QUERY needs a preflight. Your CDN may also pass QUERY requests through without caching them, because building a cache key from a body means reading the whole body first, as Section 2.7 notes. Check with your CDN before you count on cached QUERY responses. Until then, persisted documents over GET remain the common way to cache GraphQL responses in a CDN.
GraphQL query operations are safe reads with a body, and HTTP now has a method for that.
This post asked you one question and did not change anything on our server, so under RFC 10008 it is both safe and idempotent. You can read it again as many times as you like, and the result will be the same.
Sources
- RFC 10008, The HTTP QUERY Method - the method definition, caching rules,
Accept-Queryand examples - RFC 9110, HTTP Semantics - what safe and idempotent mean for every HTTP method
- Spring for GraphQL 2.1, Server Transports - opt-in
GETandQUERYsupport and their security notes - spring-framework PR #34993 -
QUERYsupport in Spring Framework 7.1 - spring-boot issue #51732 - the
spring.graphql.http.methodsproperty - graphql-over-http PR #411 - the proposal to add
QUERYto GraphQL over HTTP - HTTP QUERY ecosystem adoption tracker - which frameworks, servers and tools support the method