<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>2026-07 on Funky Si's Blog</title><link>https://www.funkysi1701.com/2026/07/</link><description>Recent content in 2026-07 on Funky Si's Blog</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><managingEditor>funkysi1701@gmail.com (Simon Foster)</managingEditor><webMaster>funkysi1701@gmail.com (Simon Foster)</webMaster><lastBuildDate>Tue, 14 Jul 2026 07:30:00 +0000</lastBuildDate><atom:link href="https://www.funkysi1701.com/2026/07/index.xml" rel="self" type="application/rss+xml"/><item><title>HTTP QUERY Explained: Safe Requests That Include a Body</title><link>https://www.funkysi1701.com/posts/2026/http-query-method/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 14 Jul 2026 07:30:00 +0000</pubDate><guid>https://www.funkysi1701.com/posts/2026/http-query-method/</guid><category term="HTTP">HTTP</category><category term="QUERY">QUERY</category><category term="RFC10008">RFC10008</category><category term="REST">REST</category><category term="ASP.NETCore">ASP.NETCore</category><category term="APIDesign">APIDesign</category><category term="OpenAPI">OpenAPI</category><category term="DotNet">DotNet</category><media:content medium="image" type="image/png" url="https://www.funkysi1701.com/images/2026/http-query-method.png"/><description>&lt;p&gt;For years, API designers have had an awkward choice when a search got too complex for a URL. Stuff it into a &lt;code&gt;GET&lt;/code&gt; query string and hit practical URI length limits, or send a body with &lt;code&gt;POST&lt;/code&gt; and pretend a read-only filter is a write. Neither option felt right.&lt;/p&gt;
&lt;p&gt;In June 2026 the IETF published &lt;a href="https://www.rfc-editor.org/rfc/rfc10008.html" target="_blank" rel="noopener noreferrer"&gt;RFC 10008&lt;/a&gt;
, which defines &lt;strong&gt;QUERY&lt;/strong&gt; — a new HTTP method that is safe and idempotent like &lt;code&gt;GET&lt;/code&gt;, but carries request content like &lt;code&gt;POST&lt;/code&gt;. That long-standing gap finally has a standard answer.&lt;/p&gt;
&lt;h2 id="the-problem-query-solves"&gt;The problem QUERY solves&lt;a class="anchor ms-1" href="#the-problem-query-solves" aria-label="Permalink: The problem QUERY solves"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GET&lt;/code&gt; is the right semantic for &amp;ldquo;please return something, and I am not asking you to change state.&amp;rdquo; It is safe, idempotent, and cacheable. The catch is where the input lives: in the URI. Complex filters, GraphQL-style documents, Elasticsearch queries, or large multi-field search payloads do not always fit comfortably in a URL. RFC 9110 suggests supporting request targets of at least 8,000 octets, but browsers, proxies, and gateways vary — and overflowing those limits is a practical failure, not a theoretical one.&lt;/p&gt;
&lt;p&gt;URI length is not the only issue. Request URIs — including query-string filters — are far more likely to appear in access logs, browser history, and bookmarks than request bodies. If your search payload contains personal data or other sensitive filters (think GDPR and PII), stuffing it into a &lt;code&gt;GET&lt;/code&gt; URL is often a compliance headache. That is one reason many teams already use &lt;code&gt;POST /search&lt;/code&gt;: the body is less exposed in everyday logging.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST&lt;/code&gt; accepts a body with a clear media type, which is perfect for structured input. The catch is what the rest of the HTTP stack is allowed to &lt;em&gt;assume&lt;/em&gt;. HTTP treats &lt;code&gt;POST&lt;/code&gt; as potentially unsafe and non-idempotent: a particular search endpoint can be a pure read in practice, but intermediaries cannot tell that from the method alone. They cannot safely auto-retry a failed &lt;code&gt;POST&lt;/code&gt; the way they can a &lt;code&gt;GET&lt;/code&gt;, and shared caches cannot treat it as a normal repeatable read. Tooling that assumes &amp;ldquo;POST means mutate&amp;rdquo; often groups a catalogue search with create/update traffic — culturally understandable, even when your handler never writes.&lt;/p&gt;
&lt;p&gt;People sometimes tried &lt;code&gt;GET&lt;/code&gt; &lt;em&gt;with&lt;/em&gt; a body. RFC 9110 is blunt about that: content on a &lt;code&gt;GET&lt;/code&gt; has no generally defined semantics, must not change the meaning of the request, and some implementations reject it because of request-smuggling concerns. That was never the answer.&lt;/p&gt;
&lt;p&gt;QUERY is the method that says what we meant all along: &lt;em&gt;process this enclosed content as a query, safely and idempotently, and return the result.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-rfc-10008-actually-defines"&gt;What RFC 10008 actually defines&lt;a class="anchor ms-1" href="#what-rfc-10008-actually-defines" aria-label="Permalink: What RFC 10008 actually defines"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From the abstract:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Compared with &lt;code&gt;GET&lt;/code&gt;, you are not asking for a representation of the target URI by itself. You are asking the target resource to run a query &lt;em&gt;within its scope&lt;/em&gt;, using the request body and &lt;code&gt;Content-Type&lt;/code&gt; to define that query. Servers must fail the request if &lt;code&gt;Content-Type&lt;/code&gt; is missing or inconsistent with the content.&lt;/p&gt;
&lt;p&gt;Key properties:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Meaning for QUERY&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The client does not request or expect a state change on the target resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idempotent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The same request can be retried after a connection failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cacheable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Successful responses may be stored and reused for subsequent QUERY requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Body required for the query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The query lives in the content, not forced into the URI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Safe&lt;/strong&gt; here is the HTTP meaning: the client is not asking to change the &lt;em&gt;target&lt;/em&gt; resource (for example &lt;code&gt;/api/products&lt;/code&gt;). That does not ban every side effect on the planet. Your server can still increment metrics, write an audit row, or — as the RFC allows — create temporary resources behind &lt;code&gt;Location&lt;/code&gt; / &lt;code&gt;Content-Location&lt;/code&gt; so results can be fetched again with &lt;code&gt;GET&lt;/code&gt;. What intermediaries can assume is that QUERY is a read against the resource you addressed, not a create or update of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Idempotent&lt;/strong&gt; means repeating the same request does not cause &lt;em&gt;additional&lt;/em&gt; side effects beyond what a single successful attempt would cause. If the connection drops after you send a QUERY, a client or proxy can send it again without worrying that the second attempt will “do something twice” — unlike a non-idempotent &lt;code&gt;POST&lt;/code&gt; that might create two orders if retried. It does &lt;em&gt;not&lt;/em&gt; mean the response is frozen forever, and it is not the same as “cache forever.” Like &lt;code&gt;GET&lt;/code&gt;, two identical QUERY calls can return different results if the underlying catalogue changed between them.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;200 OK&lt;/code&gt; means the query was processed successfully and the results are in the response content. That matches how people already think about search endpoints — now with HTTP semantics that intermediaries can trust.&lt;/p&gt;
&lt;h2 id="how-it-compares-to-get-and-post"&gt;How it compares to GET and POST&lt;a class="anchor ms-1" href="#how-it-compares-to-get-and-post" aria-label="Permalink: How it compares to GET and POST"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;GET&lt;/th&gt;
&lt;th&gt;QUERY&lt;/th&gt;
&lt;th&gt;POST (as a &amp;ldquo;search&amp;rdquo;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Request body for the query&lt;/td&gt;
&lt;td&gt;No (undefined)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safe (assumed by intermediaries)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idempotent (assumed by intermediaries)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typically cacheable as a read&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fits large / structured input&lt;/td&gt;
&lt;td&gt;Poorly (URI limits)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keeps filters out of the URI (logs / bookmarks)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-retry after failure&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Risky&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You still use &lt;code&gt;GET&lt;/code&gt; when the URI alone identifies what you want — and when you are comfortable with that URI being logged. You still use &lt;code&gt;POST&lt;/code&gt; when you are creating or changing something, or when you need a body today and cannot yet rely on QUERY end to end. QUERY is for the awkward middle: &lt;em&gt;read-only operations whose input belongs in a body&lt;/em&gt;, with semantics intermediaries can trust.&lt;/p&gt;
&lt;h2 id="caching-location-and-accept-query"&gt;Caching, Location, and Accept-Query&lt;a class="anchor ms-1" href="#caching-location-and-accept-query" aria-label="Permalink: Caching, Location, and Accept-Query"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Caching QUERY is a bit more work than caching &lt;code&gt;GET&lt;/code&gt;, because the cache key &lt;strong&gt;must&lt;/strong&gt; incorporate the request content (and related metadata). Some caches may normalise insignificant differences when building that key; clients that care can send &lt;code&gt;Cache-Control: no-transform&lt;/code&gt; as advisory guidance.&lt;/p&gt;
&lt;p&gt;The RFC also gives servers a way to hand clients a simpler follow-up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Content-Location&lt;/code&gt;&lt;/strong&gt; — a URI for a resource that holds the &lt;em&gt;results&lt;/em&gt; of this query (temporary storage of what you just got).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Location&lt;/code&gt;&lt;/strong&gt; — a URI for an &lt;em&gt;equivalent resource&lt;/em&gt; that repeats the same query via &lt;code&gt;GET&lt;/code&gt;, without resending the body.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point matters for CDNs and clients that are still catching up: after the first QUERY, subsequent hits can become ordinary &lt;code&gt;GET&lt;/code&gt;s against a stored-query URI.&lt;/p&gt;
&lt;p&gt;Discovery uses the new &lt;strong&gt;&lt;code&gt;Accept-Query&lt;/code&gt;&lt;/strong&gt; response field. A resource can advertise which query media types it understands, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;Accept-Query: application/json, application/sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you send an unsupported type, expect &lt;code&gt;415 Unsupported Media Type&lt;/code&gt;, and you may use &lt;code&gt;Accept-Query&lt;/code&gt; (or &lt;code&gt;Accept&lt;/code&gt; on error responses) to learn what to try next.&lt;/p&gt;
&lt;h2 id="cors-and-security-notes"&gt;CORS and security notes&lt;a class="anchor ms-1" href="#cors-and-security-notes" aria-label="Permalink: CORS and security notes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QUERY is &lt;strong&gt;not&lt;/strong&gt; a CORS-safelisted method. Browser &lt;code&gt;fetch&lt;/code&gt; calls will trigger a preflight &lt;code&gt;OPTIONS&lt;/code&gt; check, the same way &lt;code&gt;PUT&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt; do. That is intentional: you do not want a body-carrying cross-origin method sliding past CORS just because it is &amp;ldquo;read-like.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Putting filters in the QUERY body already helps versus a fat &lt;code&gt;GET&lt;/code&gt; query string — less sensitive material in URIs that get logged or bookmarked. That benefit disappears if you then mint temporary &lt;code&gt;Location&lt;/code&gt; or &lt;code&gt;Content-Location&lt;/code&gt; URIs that echo those filters into the path or query. The RFC warns those URIs should not include sensitive portions of the original request content.&lt;/p&gt;
&lt;h2 id="using-query-with-aspnet-core"&gt;Using QUERY with ASP.NET Core&lt;a class="anchor ms-1" href="#using-query-with-aspnet-core" aria-label="Permalink: Using QUERY with ASP.NET Core"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You do not need to wait for .NET 11 to try QUERY on the server. ASP.NET Core routing already accepts arbitrary method strings via &lt;code&gt;MapMethods&lt;/code&gt;, and recent releases expose &lt;code&gt;HttpMethods.Query&lt;/code&gt; (with &lt;code&gt;HttpMethods.IsQuery&lt;/code&gt;) so you do not have to sprinkle the literal &lt;code&gt;&amp;quot;QUERY&amp;quot;&lt;/code&gt; everywhere:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.MapMethods(&lt;span style="color:#e6db74"&gt;&amp;#34;/api/products/search&amp;#34;&lt;/span&gt;, [HttpMethods.Query], (ProductSearchRequest request) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; results = ProductCatalogue.Search(request);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; TypedResults.Ok(results);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A thin helper keeps call sites readable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HttpQueryExtensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; IEndpointConventionBuilder MapQuery(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; IEndpointRouteBuilder endpoints,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; pattern,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Delegate handler) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; endpoints.MapMethods(pattern, [HttpMethods.Query], handler);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What landed later is OpenAPI documentation. QUERY became a first-class Path Item operation in &lt;strong&gt;OpenAPI 3.2&lt;/strong&gt;. In &lt;strong&gt;.NET 11&lt;/strong&gt;, ASP.NET Core&amp;rsquo;s document generator recognises QUERY when you opt into that version — so Swagger / client generators see a proper &lt;code&gt;query&lt;/code&gt; operation instead of an oddball method string:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddOpenApi(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_2;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With OpenAPI 3.2, the operation appears as a sibling of &lt;code&gt;get&lt;/code&gt; / &lt;code&gt;post&lt;/code&gt;. On older document versions, generators may fall back to an extension such as &lt;code&gt;x-oai-additionalOperations&lt;/code&gt; so the endpoint is not silently dropped. Until you are on that stack, you can still ship QUERY endpoints and document them by hand if needed.&lt;/p&gt;
&lt;p&gt;Clients can call it with curl once the server understands the verb:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -X QUERY https://api.example.com/api/products/search &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;category&amp;#34;:&amp;#34;laptops&amp;#34;,&amp;#34;minPrice&amp;#34;:500,&amp;#34;tags&amp;#34;:[&amp;#34;ultrabook&amp;#34;,&amp;#34;16gb&amp;#34;]}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="what-to-watch-for-in-the-real-world"&gt;What to watch for in the real world&lt;a class="anchor ms-1" href="#what-to-watch-for-in-the-real-world" aria-label="Permalink: What to watch for in the real world"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Standards land before the entire ecosystem catches up. Worth checking before you announce QUERY as your public search API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proxies, API gateways, and WAFs&lt;/strong&gt; — some still allow-list only a handful of methods.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser and CDN behaviour&lt;/strong&gt; — caching QUERY responses is more complex than &lt;code&gt;GET&lt;/code&gt;; temporary &lt;code&gt;Location&lt;/code&gt; URIs help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client libraries and OpenAPI codegen&lt;/strong&gt; — support is improving, but pin versions carefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs and analytics&lt;/strong&gt; — make sure QUERY is counted as a read, not lumped in with mutating &lt;code&gt;POST&lt;/code&gt;s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For service-to-service APIs under your control, QUERY is already useful. For public browser-facing APIs, validate your edge stack and CORS setup first.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;a class="anchor ms-1" href="#why-this-matters" aria-label="Permalink: Why this matters"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HTTP methods are how we communicate intent to every hop between the client and your app. When intent and method disagree — a read that intermediaries cannot assume from &lt;code&gt;POST&lt;/code&gt;, or a body bolted onto &lt;code&gt;GET&lt;/code&gt; — caches, retries, and security tooling all have to guess.&lt;/p&gt;
&lt;p&gt;QUERY closes that gap with a small, carefully designed verb: safe, idempotent, cacheable, and allowed to carry a body. After more than a decade of drafts, &lt;a href="https://www.rfc-editor.org/rfc/rfc10008.html" target="_blank" rel="noopener noreferrer"&gt;RFC 10008&lt;/a&gt;
makes that contract official. If you maintain search or filter endpoints that never belonged in a URI, it is time to start planning for QUERY — especially on service-to-service paths you control, before you bet a public browser API on every gateway in the path understanding the verb.&lt;/p&gt;</description></item></channel></rss>