RFC 10008
The HTTP QUERY Method
RFC 10008: The HTTP QUERY Method π
okay bestie, let's set the scene π this is RFC 10008, published by the Internet Engineering Task Force (IETF) in June 2026. It's a Standards Track document, which means it's the real deal and not a vibes-only draft β¨ The ISSN is 2070-1721 πΈ The authors are J. Reschke (greenbytes), J.M. Snell (Cloudflare), and M. Bishop (Akamai), so that's three brilliant brains on this one π§ The title block doesn't list anything it obsoletes or updates, so it isn't replacing or patching any other RFC.
Abstract β¨
okay so the abstract is basically the TL;DR π¦ It defines the QUERY method for HTTP. A QUERY asks the request target to process the enclosed content in a safe and idempotent way, and then to respond with the result. It's giving POST vibes, but QUERY requests can be automatically repeated or restarted without worrying about partial state changes π
Status of This Memo π
this is an Internet Standards Track document π
this one is a product of the IETF, and it represents the consensus of the IETF community. It went through public review and got approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 7841 π
for the current status, any errata, and how to send feedback on this doc, go to https://www.rfc-editor.org/info/rfc10008 π
Copyright Notice π
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.
this doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the publication date. Please read those carefully, because they spell out your rights and restrictions for this document. Code Components pulled out of this document have to include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Revised BSD License βοΈ
Table of Contents π
1. Introduction
1.1. Terminology
1.2. Notational Conventions
2. QUERY Method
2.1. Media Types and Content Negotiation
2.2. Equivalent Resource
2.3. Content-Location Response Field
2.4. Location Response Field
2.5. Redirection
2.6. Conditional Requests
2.7. Caching
2.8. Range Requests
3. The Accept-Query Header Field
4. Security Considerations
5. IANA Considerations
5.1. Registration of the QUERY Method
5.2. Registration of the Accept-Query Field
6. References
6.1. Normative References
6.2. Informative References
Appendix A. Examples
A.1. Simple Query
A.2. Discovery of QUERY Support
A.3. Discovery of QUERY Formats
A.4. Content-Location, Location, and Indirect Responses
A.4.1. Using Content-Location
A.4.2. Using Location
A.4.3. Indirect Responses
A.5. Conditional Requests
A.6. More Query Formats
Appendix B. Selection of the Method Name 'QUERY'
Acknowledgements
Contributors
Authors' Addresses
1. Introduction π¦
so this spec defines the HTTP QUERY request method π It's a way to make a safe, idempotent request (Section 9.2 of [HTTP]), and that request carries a representation that describes how the target resource should process it.
the classic query pattern looks like this π
GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
Host: example.org
but once the data is too voluminous to fit into the request's URI, this pattern gets messy π Here's why:
- size limits are often not known ahead of time, because a request can pass through lots of uncoordinated systems. (Side note: Section 4.1 of [HTTP] recommends that senders and recipients support at least 8000 octets π)
- expressing certain kinds of data in the target URI is inefficient, because you have to do the overhead of encoding that data into a valid URI π
- request URIs are more likely to get logged than request content, and they can also show up in bookmarks π
- encoding queries directly into the request URI basically turns every possible combo of query inputs into its own distinct resource π€―
so people often use HTTP POST for queries instead, like in this example π«Ά The query input goes in the request content, not in the request URI's query component.
POST /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
q=foo&limit=10&sort=-published
the problem is that, without specific knowledge of the resource and server you're talking to, it's not obvious that a safe, idempotent query is happening here π
enter QUERY πΈ It sits right between GET and POST, and the example above becomes:
QUERY /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
q=foo&limit=10&sort=-published
just like POST, the query input rides in the request content instead of the URI. The big difference is that QUERY is explicitly safe and idempotent, which means things like caching and automatic retries can actually work πβ¨
there's also a design principle that any important resource ought to be identifiable by a URI π§ So this spec describes how a server can assign URIs to the query itself, or to a specific query result, for use later in a GET request.
here's the summary, bestie π
+==========+=================+=================+===================+
| |GET |QUERY | POST |
+==========+=================+=================+===================+
|Safe |yes |yes | potentially no |
+----------+-----------------+-----------------+-------------------+
|Idempotent|yes |yes | potentially no |
+----------+-----------------+-----------------+-------------------+
|URI for |yes (by |optional | no |
|query |definition) |(Location | |
|itself | |response field) | |
+----------+-----------------+-----------------+-------------------+
|URI for |optional |optional | optional |
|query |(Content-Location|(Content-Location| (Content-Location |
|result |response field) |response field) | response field) |
+----------+-----------------+-----------------+-------------------+
|Cacheable |yes |yes | yes, but only for |
| | | | future GET or |
| | | | HEAD requests |
+----------+-----------------+-----------------+-------------------+
|Content |"no defined |expected | expected |
|(body) |semantics" |(semantics per | (semantics per |
| | |target resource) | target resource) |
+----------+-----------------+-----------------+-------------------+
Table 1: Summary of Relevant Method Properties
1.1. Terminology π
this doc uses terminology defined in Section 3 of [HTTP] π
on top of that, it uses URI query parameter for the parameters in the query component of a URI (Section 4.2.2 of [HTTP]), and query content for the request content (Section 6.4 of [HTTP]) of a QUERY request π
1.2. Notational Conventions π
the big keywords in this document, "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL", are read the BCP 14 way ([RFC2119] [RFC8174]). That only happens when, and only when, they show up in ALL CAPS, just like shown here β
2. QUERY Method π
so the QUERY method starts a server-side query π₯ GET asks for a representation of whatever's at the target URI (Section 7.1 of [HTTP]). QUERY is different: it asks the target resource to run a query operation within that resource's scope.
the content of the request and its media type together define the query π§© The origin server works out the scope of the operation from the target resource.
Servers MUST fail the request if the Content-Type request field ([HTTP], Section 8.3) is missing, or if it doesn't match the request content π«
like with every HTTP method, the query part of the target URI helps identify which resource is being queried π Whether and how it directly changes the query result depends on the resource, so that's out of scope for this spec π
QUERY requests are safe with regard to the target resource ([HTTP], Section 9.2.1). That means the client doesn't ask for, or expect, any change to the target resource's state π§ββοΈ That still lets the server create extra HTTP resources so more info can be retrieved through them (see Sections 2.3 and 2.4) π¦
QUERY requests are also idempotent ([HTTP], Section 9.2.2) π They can be retried or repeated when needed, for example after a connection failure π
as per Section 15.3 of [HTTP], a 2xx (Successful) response code means the request was successfully received, understood, and accepted β
and specifically, a 200 (OK) response means the query was successfully processed, and the results of that processing are enclosed as the response content πβ¨
2.1. Media Types and Content Negotiation π
okay so a QUERY request's meaning depends on BOTH the request content AND the metadata around it, like the media type ([HTTP], Section 8.3.1) π and if the content and metadata don't match, that's a problem. Any problem with requests where content and metadata are inconsistent MUST be rejected with a 4xx (Client Error) response ([HTTP], Section 15.5). π ββοΈ
Here's the breakdown of the different ways things can go wrong, plus which status codes are the right ones to use:
- If a request has no media type info, it's incorrect by definition and needs to fail with a 4xx status code, like 400 (Client Error). π
- If a media type is specified but the resource doesn't support it, a 415 (Unsupported Media Type) is the move. This also covers the case where the media type is known in general, but it doesn't have the semantics a QUERY to that target resource needs. In both cases, the Accept-Query response field (Section 3) can tell the client which media types ARE supported. π«Ά
- If a media type is specified but doesn't match the actual request content, a 400 (Bad Request) can be returned. A server is not allowed to guess a media type from the request content and then override a missing or "erroneous" value (i.e., "content sniffing"). No sniffing, bestie. π
- If the media type is specified and understood, the content matches it, but the query can't be processed because of what the query actually says, the status 422 (Unprocessable Content) can be used. For example, a syntactically correct SQL query that points at a table that doesn't exist. π₯
- If the client asks for a specific response media type using the Accept field ([HTTP], Section 12.5.1) and the resource doesn't support it, a status code of 406 (Not Acceptable) is appropriate. π
2.2. Equivalent Resource π¦
The equivalent resource for any QUERY request is a resource that responds to GET requests, represents that QUERY request and its target, and takes both the message content and the metadata into account (Section 6 of [HTTP]). This especially includes representation metadata (Section 8 of [HTTP]), like the content's media type. β¨
So basically, the equivalent resource is derived from the resource that implements QUERY by folding in the request content. π§
The term equivalent resource is a handy tool for defining how other HTTP stuff works, like selected representations. Servers can assign URIs to these resources, but they don't have to (see Section 1.1 of [URI]). If they do, those resources become accessible for GET requests. πΈ
2.3. Content-Location Response Field π
A successful response (2xx, Section 15.3 of [HTTP]) can include a Content-Location header field containing an identifier for a resource that matches the results of the operation. See Section 8.7 of [HTTP] for the details. This is the server basically saying, "hey, you can send a GET request to this URI to pull up the results of the query we just ran." The indicated resource might be temporary, so don't get too attached. π₯Ή
See Appendix A.4.1 for an example. π
2.4. Location Response Field π
A server can assign a URI to the equivalent resource (Section 2.2) of a QUERY request. If it does, that URI can go in the Location header field of the 2xx response (see Section 10.2.2 of [HTTP]). This is a claim that a client can send a GET request to that URI to repeat the query without resending the query content. Iconic. π This resource's URI might be temporary too. If a future request fails, the client can retry using the original QUERY request target and the content it already submitted. π
See Appendix A.4.2 for an example. β
2.5. Redirection π¦
Sometimes the server decides to respond to a QUERY request indirectly by redirecting the user agent to a different URI (see Section 15.4 of [HTTP]). π§
A response with status code 301 (Moved Permanently, [HTTP], Section 15.4.2) or 308 (Permanent Redirect, [HTTP], Section 15.4.9) means the target resource has permanently moved to a different URI, which is given in the Location response field ([HTTP], Section 10.2.2). Likewise, a response with status code 302 (Found, [HTTP], Section 15.4.3) or 307 (Temporary Redirect, [HTTP], Section 15.4.8) means the target resource has temporarily moved. In all four cases, the server is suggesting that the user agent can accomplish its original QUERY request by sending a similar QUERY request to the new target URI in the Location. Main character redirect energy. π
Note that the exceptions for turning a POST into a GET after a 301 or 302 response do NOT apply to QUERY requests. Not the vibe. π ββοΈ
A response to QUERY with status code 303 (See Other, Section 15.4.4 of [HTTP]) means the original query can be done with a normal retrieval request on the URI in the Location response field ([HTTP], Section 10.2.2). For HTTP, that means sending a GET request to the new target URI, as shown in the example in Appendix A.4.3. π
2.6. Conditional Requests π
The selected representation (Section 3.2 of [HTTP]) of a QUERY request is the same as for a GET request to that QUERY request's equivalent resource (Section 2.2). π«Ά
A conditional QUERY requests that the selected representation (i.e., the query results after any content negotiation) be returned in the response only under the circumstances described by the conditional header field(s), as defined in Section 13 of [HTTP]. π―
See Appendix A.5 for examples. π·
2.7. Caching π―
The response to a QUERY method is cacheable, and a cache MAY use it to satisfy subsequent QUERY requests as per Section 4 of [HTTP-CACHING]. πΎ
The cache key for a QUERY request (Section 2 of [HTTP-CACHING]) MUST incorporate the request content (Section 6 of [HTTP-CACHING]) and the related metadata (Section 8 of [HTTP]). This part is non-negotiable, periodt. π
To make the cache more efficient, caches MAY strip out semantically insignificant differences from the request content and related metadata first. For instance, by:
- removing content encoding(s) (Section 8.4 of [HTTP]).
- normalizing based on knowledge of format conventions, as indicated by any media subtype suffix in the request's
Content-Typefield (e.g.,"+json"; see Section 4.2.8 of [RFC6838]). - normalizing based on knowledge of the semantics of the content itself, as indicated by the request's
Content-Typefield.
Note that any transformation like this is done solely to generate a cache key. It does NOT change the request itself. π§Ό
Clients can use the no-transform cache directive (Section 5.2.1.6 of [HTTP-CACHING]) to say they want NO such transformation to happen. But heads up, this directive is just advisory. π€·ββοΈ
Caching QUERY responses is way more complex than caching GET responses, because the cache needs to read the request's whole content before it can figure out the cache key. π If a QUERY response includes a Location response field (Section 2.4) pointing to a URI for an equivalent resource (Section 2.2), clients can switch to GET for later requests, which makes processing simpler. Big brain move. π§
2.8. Range Requests π
Range Requests for QUERY work exactly the same as they do for GET, as defined in Section 14 of [HTTP]. Byte Range Requests (the only range unit defined at the time of writing), however, don't offer much value for QUERY results. π
Query formats often have their own built-in way of limiting results or paging through them, like FETCH FIRST ... ROWS ONLY in SQL. Those built-in features are expected to be used instead of HTTP Range Requests. Use the tools you already have, babe. π§ββοΈ
3. The Accept-Query Header Field β¨
The Accept-Query response header field lets a resource directly signal that it supports the QUERY method, and it names the specific query format media type(s) that may be used. π£
Accept-Query contains a list of media ranges (Section 12.5.1 of [HTTP]) using "Structured Fields" syntax [STRUCTURED-FIELDS]. Media ranges are represented by a List Structured Header Field of either Tokens or Strings, holding the media range value without parameters. π°
Media type parameters, if there are any, get mapped to Structured Field Parameters with the String or Token type. Choosing Token versus String is semantically insignificant. Recipients MAY convert Tokens to Strings, but they MUST NOT process them differently based on the type they received. Same vibe, different outfit. π
Media types don't map exactly to Tokens. For instance, they allow a leading digit. In cases like these, the String format needs to be used. π€
The only supported uses of wildcards are */*, which matches any type, and xxxx/*, which matches any subtype of the indicated type. π
The order of the types listed in the field value is not significant. πββοΈ
The value of the Accept-Query field applies to every URI on the server that shares the same path. In other words, the query component is ignored. If requests to the same resource return different Accept-Query values, the most recently received fresh value (per Section 4.2 of [HTTP-CACHING]) is used. π°οΈ
For example:
Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
Even though this field's syntax looks similar to other fields, like Accept (Section 12.5.1 of [HTTP]), it's a Structured Field, so it MUST be processed as specified in Section 4 of [STRUCTURED-FIELDS]. Don't let the lookalike fool you. π΅οΈββοΈπ
4. Security Considerations π
The QUERY method is subject to the same general security considerations as all HTTP methods, as described in [HTTP]. Take it seriously, bestie. π€
QUERY can be used as an alternative to passing request information in the URI (e.g., in the query component). This is preferred in some cases, because the URI is more likely to be logged or otherwise processed by intermediaries than the request content. In other cases, where the query contains sensitive information, the potential for the URI to be logged might be the reason to pick QUERY over GET. π΅οΈ
If a server creates a temporary resource to represent the results of a QUERY request (e.g., for use in the Location or Content-Location field), assigns a URI to that resource, and the request contains sensitive information that cannot be logged, then that URI SHOULD be chosen such that it does not include any sensitive portions of the original request content. Keep the secrets out of the link, okay?! π€«
Caches that normalize QUERY content incorrectly, or in ways that are significantly different from how the resource processes the content, can return an incorrect response if the normalization results in a false positive. This one is a real danger zone. π
A QUERY request from user agents implementing Cross-Origin Resource Sharing (CORS) will require a "preflight" request, because QUERY does not belong to the set of CORS-safelisted methods (see [FETCH]). Extra step, but it's giving safety. π‘οΈ
5. IANA Considerations π
5.1. Registration of the QUERY Method π
IANA has added the QUERY method to the "Hypertext Transfer Protocol (HTTP) Method Registry" at <http://www.iana.org/assignments/http-methods> (see Section 16.3.1 of [HTTP]). Officially in the registry, no cap. π₯³
+=============+======+============+========================+
| Method Name | Safe | Idempotent | Specification |
+=============+======+============+========================+
| QUERY | yes | yes | Section 2 of RFC 10008 |
+-------------+------+------------+------------------------+
Table 2: QUERY Method Definition
5.2. Registration of the Accept-Query Field β¨
okay so IANA officially added Accept-Query to the "Hypertext Transfer Protocol (HTTP) Field Name Registry" at <https://www.iana.org/assignments/http-fields> (see Section 16.1.1 of [HTTP]) ππ. here's the entry, and yes it's giving official π
+==============+===========+============+==============+==========+
| Field Name | Status | Structured | Reference | Comments |
| | | Type | | |
+==============+===========+============+==============+==========+
| Accept-Query | permanent | List | Section 3 of | |
| | | | RFC 10008 | |
+--------------+-----------+------------+--------------+----------+
Table 3: Accept-Query Field Definition
6. References π
6.1. Normative References
these are the ones the spec leans on hard π€ you really want these bookmarked
- [HTTP] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, June 2022, <https://www.rfc-editor.org/info/rfc9110>.
- [HTTP-CACHING] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Caching", STD 98, RFC 9111, DOI 10.17487/RFC9111, June 2022, <https://www.rfc-editor.org/info/rfc9111>.
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.
- [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
- [STRUCTURED-FIELDS] Nottingham, M. and P. Kamp, "Structured Field Values for HTTP", RFC 9651, DOI 10.17487/RFC9651, September 2024, <https://www.rfc-editor.org/info/rfc9651>.
- [URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <https://www.rfc-editor.org/info/rfc3986>.
6.2. Informative References
these ones are extra context, the "nice to know" shelf πΈ
- [FETCH] WHATWG, "FETCH", WHATWG Living Standard, <https://fetch.spec.whatwg.org>. Commit snapshot: https://fetch.spec.whatwg.org/commit-snapshots/3bab31a55154bda73f25b45a23df718616f2f64e/
- [RFC3253] Clemm, G., Amsden, J., Ellison, T., Kaler, C., and J. Whitehead, "Versioning Extensions to WebDAV (Web Distributed Authoring and Versioning)", RFC 3253, DOI 10.17487/RFC3253, March 2002, <https://www.rfc-editor.org/info/rfc3253>.
- [RFC4918] Dusseault, L., Ed., "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)", RFC 4918, DOI 10.17487/RFC4918, June 2007, <https://www.rfc-editor.org/info/rfc4918>.
- [RFC5323] Reschke, J., Ed., Reddy, S., Davis, J., and A. Babich, "Web Distributed Authoring and Versioning (WebDAV) SEARCH", RFC 5323, DOI 10.17487/RFC5323, November 2008, <https://www.rfc-editor.org/info/rfc5323>.
- [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, DOI 10.17487/RFC6838, January 2013, <https://www.rfc-editor.org/info/rfc6838>.
- [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.
- [RFC9535] GΓΆssner, S., Ed., Normington, G., Ed., and C. Bormann, Ed., "JSONPath: Query Expressions for JSON", RFC 9535, DOI 10.17487/RFC9535, February 2024, <https://www.rfc-editor.org/info/rfc9535>.
- [URL] WHATWG, "URL", WHATWG Living Standard, <https://url.spec.whatwg.org>. Commit snapshot: https://url.spec.whatwg.org/commit-snapshots/52526653e848c5a56598c84aa4bc8ac9025fb66b/
- [XSLT] Kay, M., Ed., "XSL Transformations (XSLT) Version 3.0", W3C Recommendation, 8 June 2017, <https://www.w3.org/TR/2017/REC-xslt-30-20170608/>. Latest version available at https://www.w3.org/TR/xslt-30/.
Appendix A. Examples π
these examples are just for illustration π«Ά real queries that are this short? honestly just use GET, it's the better fit
the media type in most of them is "application/x-www-form-urlencoded" (the one browser user clients send with POST requests, defined in "application/x-www-form-urlencoded" (https://url.spec.whatwg.org/#application/x-www-form-urlencoded) in [URL]). the Content-Length fields are left out to keep things short π
A.1. Simple Query π
here's a simple query that gets a direct response:
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json
select=surname,givenname,email&limit=10&match=%22email=*@example.*%22
Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{ "surname": "Smith",
"givenname": "John",
"email": "smith@example.org" },
{ "surname": "Jones",
"givenname": "Sally",
"email": "sally.jones@example.com" },
{ "surname": "Dubois",
"givenname": "Camille",
"email": "camille.dubois@example.net" }
]
A.2. Discovery of QUERY Support π
a simple way to find out if QUERY is supported is the OPTIONS (Section 9.3.7 of [HTTP]) method π§
OPTIONS /contacts HTTP/1.1
Host: example.org
Response:
HTTP/1.1 200 OK
Allow: GET, QUERY, OPTIONS, HEAD
the Allow response field (Section 10.2.1 of [HTTP]) shows the set of supported methods on the specified resource π
there are other options too. you can just try a QUERY request without knowing anything about server support first π¦ the server would then either process the request, or it could respond with a 4xx status such as 405 (Method Not Allowed, Section 15.5.6 of [HTTP]), including the Allow response field.
A.3. Discovery of QUERY Formats π§
checking which media types QUERY accepts is possible through the Accept-Query response field (Section 3):
HEAD /contacts HTTP/1.1
Host: example.org
Response:
HTTP/1.1 200 OK
Content-Type: application/xhtml
Accept-Query: application/x-www-form-urlencoded, application/sql
which responses will contain Accept-Query depends on the resource being accessed π
an alternative to checking Accept-Query is to make a QUERY request and then, if you get a 4xx status such as a 415 response (Unsupported Media Type, Section 15.5.16 of [HTTP]), look at the Accept response field (Section 12.5.1 of [HTTP]) π
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/xhtml
Accept: application/x-www-form-urlencoded, application/sql
A.4. Content-Location, Location, and Indirect Responses πΈ
as described in Sections 2.3 and 2.4, the Content-Location and Location response fields in success responses (2xx, Section 15.3 of [HTTP]) give you a way to find alternate resources that will respond to GET requests. they can hold either the received result of the request, or serve future requests for the same operation β¨ going back to the example from Appendix A.1:
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json
select=surname,givenname,email&limit=10&match=%22email=*@example.*%22
Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /contacts/stored-results/17
Location: /contacts/stored-queries/42
Last-Modified: Sat, 25 Aug 2012 23:34:45 GMT
Date: Sun, 17 Nov 2024, 16:10:24 GMT
[
{ "surname": "Smith",
"givenname": "John",
"email": "smith@example.org" },
{ "surname": "Jones",
"givenname": "Sally",
"email": "sally.jones@example.com" },
{ "surname": "Dubois",
"givenname": "Camille",
"email": "camille.dubois@example.net" }
]
A.4.1. Using Content-Location π¦
the Content-Location response field from above points to a resource holding the result for the QUERY response it came on π
GET /contacts/stored-results/17 HTTP/1.1
Host: example.org
Accept: application/json
Response:
HTTP/1.1 200 OK
Last-Modified: Sat, 25 Aug 2012 23:34:45 GMT
Date: Sun, 17 Nov 2024, 16:10:25 GMT
[
{ "surname": "Smith",
"givenname": "John",
"email": "smith@example.org" },
{ "surname": "Jones",
"givenname": "Sally",
"email": "sally.jones@example.com" },
{ "surname": "Dubois",
"givenname": "Camille",
"email": "camille.dubois@example.net" }
]
heads up π¨ there's no guarantee the server keeps this resource around forever, so after an error response, the client would need to redo the original QUERY request to get a new alternative location π
A.4.2. Using Location π§ββοΈ
the Location response field points to a resource that will respond to GET with a current result for the same process and parameters as the original QUERY request π
GET /contacts/stored-queries/42 HTTP/1.1
Host: example.org
Accept: application/json
in this example, one entry got removed at 2024-11-17T16:12:01Z (as the Last-Modified field shows), so the response only has two entries:
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Sun, 17 November 2024, 16:12:01 GMT
ETag: "42-1"
Date: Sun, 17 Nov 2024, 16:13:17 GMT
[
{ "surname": "Smith",
"givenname": "John",
"email": "smith@example.org" },
{ "surname": "Dubois",
"givenname": "Camille",
"email": "camille.dubois@example.net" }
]
assuming the server still exposes the resource and the query result hasn't changed, a later conditional GET request with the following:
If-None-Match: "42-1"
would get a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) ππ«Ά
A.4.3. Indirect Responses π«
servers can send "indirect" responses (Section 2.5) using the status code 303 (See Other, Section 15.4.4 of [HTTP]) π·
given the request at the start of Appendix A.4, a server might respond with:
HTTP/1.1 303 See Other
Content-Type: text/plain
Date: Sun, 17 Nov 2024, 16:13:17 GMT
Location: /contacts/stored-queries/42
See stored query at "/contacts/stored-queries/42".
this is pretty much like putting Location on a direct response, except no result for the query comes back. it lets the server just generate or reuse an alternative resource, and that resource can then be used like in Appendix A.4.2 πβ¨
A.5. Conditional Requests β¨
okay so this one is my fave π¦ picture a resource that does QUERY and takes application/sql and application/xslt+xml [XSLT] as request media types, and it can hand back text/csv responses. The data set it's querying has RFC document info in it, and the query groups everything by decade π
QUERY /rfc-index.xml HTTP/1.1
Host: example.org
Date: Sun, 7 Sep 2025, 00:00:00 GMT
Content-Type: application/xslt+xml
Accept: text/csv
...Query content using XSLT...
Response:
HTTP/1.1 200 OK
Date: Sun, 7 Sep 2025, 00:00:00 GMT
Location: /stored-queries/4815162342
Content-Type: text/csv
Accept-Query: "application/sql", "application/xslt+xml"
Last-Modified: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Encoding, Content-Type
decade, total, with errata, % with errata, average page count
1960, 26, 5, 19.2, 5.3
1970, 666, 18, 2.7, 6.1
1980, 376, 44, 11.7, 23.4
1990, 1593, 269, 16.9, 25.5
2000, 2888, 1048, 36.3, 27.3
2010, 2954, 895, 30.3, 26.1
2020, 1133, 230, 20.3, 26.2
Here, the server gave the path /stored-queries/4815162342 to the equivalent resource (Section 2.4), so you can use it later with GET π
Later on, the client repeats the query but says "only send me stuff if it changed" π
QUERY /rfc-index.xml HTTP/1.1
Host: example.org
Date: Mon, 8, Sep 2025, 11:00:00 GMT
Content-Type: application/sql
Accept: text/csv
If-Modified-Since: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Type
...Same query, but using SQL...
The data being queried didn't change, so the server replies with π
HTTP/1.1 304 Not Modified
Date: Mon, 8 Sep 2025, 11:00:00 GMT
Content-Type: text/csv
Location: /stored-queries/4815162342
Accept-Query: "application/sql", "application/xslt+xml"
Last-Modified: Sun, 31 Aug 2025, 08:44:00 GMT
Vary: Accept-Query, Content-Type
Since the server gave a URI for the equivalent resource, that resource can be accessed with GET. The best part is that this skips resending the query request's content all over again π
GET /stored-queries/4815162342 HTTP/1.1
Host: example.org
Date: Sun, 21, Sep 2025, 12:08:00 GMT
Accept: text/csv
If-Modified-Since: Sun, 31 Aug 2025, 00:00:00 GMT
This time the state of the data set really did change, so new content comes back π
HTTP/1.1 200 OK
Date: Sun, 21, Sep 2025, 12:08:00 GMT
Content-Type: text/csv
Last-Modified: Thu, 18 Sep 2025, 19:56:00 GMT
Vary: Accept-Query, Content-Encoding, Content-Type
decade, total, with errata, % with errata, average page count
1960, 26, 5, 19.2, 5.3
1970, 666, 18, 2.7, 6.1
1980, 376, 44, 11.7, 23.4
1990, 1593, 269, 16.9, 25.5
2000, 2888, 1048, 36.3, 27.3
2010, 2954, 895, 30.3, 26.1
2020, 1133, 230, 20.3, 26.2
(Note the change in the row for this decade.) π
The diagrams below show how conditional requests work, and how they can look different when a URI is assigned to the equivalent resource (and the client is taking advantage of it). The made-up field name "Validator" is just for demo purposes π§
Client Resource
| |
| QUERY with content |
+---------------------------------------->|
| |
| 200 OK |
| Validator: foo |
|<----------------------------------------+
| |
| QUERY with content |
| (conditional on 'foo') |
+---------------------------------------->|
| |
| 304 Not Modified |
| Validator: foo |
|<----------------------------------------+
| |
| +--------------+
| | State Change |
| +--------------+
| |
| QUERY with content |
| (conditional on 'foo') |
+---------------------------------------->|
| |
| 200 OK |
| Validator: bar |
|<----------------------------------------+
| |
Figure 1: Data Flow with QUERY Only
Client Resource
| |
| QUERY with content | Equivalent Resource
+------------------------------>| (generates /xyz)
| +---------------------------o
| | |
| 200 OK | |
| Validator: foo | |
| Location: /xyz | |
|<------------------------------+ |
| | |
| GET |
| (conditional on 'foo') |
+---------------------------------------------------------->|
| |
| 304 Not Modified |
| Validator: foo |
|<----------------------------------------------------------+
| |
| +--------------+
| | State Change |
| +--------------+
| GET |
| (conditional on 'foo') |
+---------------------------------------------------------->|
| |
| 200 OK |
| Validator: bar |
|<----------------------------------------------------------+
| |
Figure 2: Data Flow with GET to Equivalent Resource
A.6. More Query Formats π¦
The examples below show requests on a JSON-shaped [RFC8259] database of RFC errata π
The request below uses eXtensible Stylesheet Language Transformations (XSLT) to pull out errata info summarized per year and the defined errata types β¨
QUERY /errata.json HTTP/1.1
Host: example.org
Content-Type: application/xslt+xml
Accept: application/xml, text/csv
<transform xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:j="http://www.w3.org/2005/xpath-functions"
version="3.0">
<output method="text"/>
<param name="input"/>
<variable name="json"
select="json-to-xml(unparsed-text($input))"/>
<variable name="sc">errata_status_code</variable>
<variable name="sd">submit_date</variable>
<template match="/">
<text>year, total, rejected, verified, hdu, reported</text>
<text> </text>
<variable name="en" select="$json//j:map"/>
<for-each-group select="$en"
group-by="substring-before(j:string[@key=$sd],'-')">
<sort select="current-grouping-key()"/>
<variable name="year" select="current-grouping-key()"/>
<variable name="errata" select=
"$en[$year=substring-before(j:string[@key=$sd],'-')]"/>
<value-of select="concat(
$year,
', ',
count($errata),
', ',
count($errata['Rejected'=j:string[@key=$sc]]),
', ',
count($errata['Verified'=j:string[@key=$sc]]),
', ',
count(
$errata['Held for Document Update'=j:string[@key=$sc]]),
', ',
count($errata['Reported'=j:string[@key=$sc]]),
' ')"/>
</for-each-group>
</template>
</transform>
Response:
HTTP/1.1 200 OK
Content-Type: text/csv
Accept-Query: "application/jsonpath", "application/xslt+xml"
Date: Wed, 19 Feb 2025, 17:10:01 GMT
year, total, rejected, verified, hdu, reported
2000, 14, 0, 14, 0, 0
2001, 72, 1, 70, 1, 0
2002, 124, 8, 104, 12, 0
2003, 63, 0, 61, 2, 0
2004, 89, 1, 83, 5, 0
2005, 156, 10, 96, 50, 0
2006, 444, 54, 176, 214, 0
2007, 429, 48, 188, 193, 0
2008, 423, 52, 165, 206, 0
2009, 331, 39, 148, 144, 0
2010, 538, 80, 232, 222, 4
2011, 367, 47, 170, 150, 0
2012, 348, 54, 149, 145, 0
2013, 341, 61, 169, 106, 5
2014, 342, 73, 180, 72, 17
2015, 343, 79, 145, 89, 30
2016, 295, 46, 122, 82, 45
2017, 303, 46, 120, 84, 53
2018, 350, 61, 118, 98, 73
2019, 335, 47, 131, 94, 63
2020, 387, 68, 117, 123, 79
2021, 321, 44, 148, 63, 66
2022, 358, 37, 198, 40, 83
2023, 262, 38, 121, 33, 70
2024, 322, 33, 125, 23, 141
9999, 1, 0, 0, 1, 0
Note the Accept-Query response field saying another query format, JSONPath [RFC9535], is supported too π The request below would report the identifiers of all rejected errata submitted since 2024:
QUERY /errata.json HTTP/1.1
Host: example.org
Content-Type: application/jsonpath
Accept: application/json
$..[
?@.errata_status_code=="Rejected"
&& @.submit_date>"2024"
]
["doc-id"]
Response:
HTTP/1.1 200 OK
Content-Type: application/json
Accept-Query: "application/jsonpath", "application/xslt+xml"
Date: Thu, 20 Feb 2025, 09:55:42 GMT
Last-Modified: Thu, 20 Feb 2025 06:10:01 GMT
[
"RFC1185","RFC8407","RFC6350","RFC8467","RFC1157","RFC9543",
"RFC9076","RFC7656","RFC2822","RFC9460","RFC2104","RFC6797",
"RFC9499","RFC9557","RFC2131","RFC2328","RFC9001","RFC3325",
"RFC9438","RFC2526","RFC2985","RFC7643","RFC9132","RFC6376",
"RFC9110","RFC9460","RFC7748","RFC9497","RFC8463","RFC4035",
"RFC7239","RFC9083","RFC9537","RFC9537","RFC9420","RFC9000",
"RFC9656","RFC9110","RFC2324","RFC2549","RFC6797","RFC2549",
"RFC8894"
]
Appendix B. Selection of the Method Name 'QUERY' π
The "Hypertext Transfer Protocol (HTTP) Method Registry" (<http://www.iana.org/assignments/http-methods>) already has three other methods with the properties "safe" and "idempotent": PROPFIND [RFC4918], REPORT [RFC3253], and SEARCH [RFC5323].
It would have been possible to reuse any of these, updating it so it matches what this spec defines as the new method QUERY. Honestly, the early drafts of this spec even used SEARCH π
The method name QUERY ultimately won because:
- The alternatives use a generic media type for the request content (
application/xml), and the semantics of the request depend solely on the request content. - Furthermore, they all come from the WebDAV activity, which many people have mixed feelings about π¬
QUERYcaptures the relation with the URI's query component really well π
Acknowledgements π«Ά
okay bestie, the HTTP Working Group deserves a whole parade π We thank all of them for their ideas, reviews, and feedback, because this spec wouldn't exist without that squad π
The following individuals get extra special recognition β¨π: Carsten Bormann, Mark Nottingham, Martin Thomson, Michael Thornburgh, Roberto Polli, Roy Fielding, and Will Hawkins. Literal legends π
Contributors π¦
Ashok Malhotra was part of the early discussions that led to this specification πΈ Here's how to reach them:
- Ashok Malhotra
- Email:
malhotrasahib@gmail.com
Discussion on this HTTP method was reopened by AsbjΓΈrn Ulsberg during the HTTP Workshop in 2019 π₯ Main character energy, honestly π
- AsbjΓΈrn Ulsberg
- Email:
asbjorn@ulsberg.no - URI:
https://asbjor.nu/
Authors' Addresses π
Here are the people who actually wrote this thing π§ Slay, and reach out if you've got questions π
Julian Reschke
greenbytes GmbH
Hafenweg 16
48155 MΓΌnster
Germany
Email: julian.reschke@greenbytes.de
URI: https://greenbytes.de/tech/webdav/
James M Snell
Cloudflare
Email: jasnell@gmail.com
Mike Bishop
Akamai
Email: mbishop@evequefou.be
That's the whole doc, bestie πβ¨ Thanks for hanging out with me through all five parts π«Άπ
π¦ where this page comes from
- ietf: rfc10008 2026-06
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms