๐ S49: HTTP QUERY Method Support (RFC 10008)
July 1, 2026 ยท View on GitHub
Status: โ
Implemented
Owner: Cesar Romero & Engineering Team
Created: 2026-06-30
Dependencies: S39 (Native Server Engine), S20 (Fluent REST Evolution)
Enables: Safe, idempotent complex data retrieval with request bodies, caching of query operations, and standard-compliant resource discovery via Accept-Query.
1. Goal
Implement support for the standardized HTTP QUERY method (RFC 10008) across both the client-side (TRestClient / TRestRequest) and server-side (IApplicationBuilder / routing engines) components of the Dext Framework. This enables clients to perform complex read-only queries with structured request bodies (JSON, SQL, GraphQL, etc.) in a safe, idempotent, and cacheable manner, without the URL length limits of GET or the semantic misuse of POST.
2. Technical Context & Objectives
Traditionally, web API developers faced a compromise when transmitting complex queries:
- GET is safe and idempotent but lacks a request body. Queries must be placed in the URL query string, risking length limits, URL encoding bottlenecks, and exposure in logs.
- POST supports a request body but is semantically unsafe and non-idempotent, preventing downstream caching (e.g., CDN and proxy caching).
RFC 10008 defines the QUERY method, which is:
- Safe & Idempotent: Semantically read-only; multiple identical requests yield identical side-effects.
- Request Body Enabled: Allows full structured request payloads.
- Cacheable: Responses can be cached based on both the URI and the request body content (via custom cache-key computation).
- Discoverable: Advertised using the
Accept-Queryresponse header to list supported media types.
Objectives
- Extend the client-side Rest Client with
hmQUERYmethod enum and fluent methods. - Implement server-side routing support for the
QUERYmethod usingMapQuery. - Support the
Accept-Queryheader to declare accepted request body formats. - Integrate query caching using a request body hashing strategy.
- Guarantee high performance and zero-allocation processing of incoming request methods and headers.
3. Scope & Implementation
3.1 Rest Client & Request Executor Changes
We will introduce hmQUERY to the TDextHttpMethod enum and map the string "QUERY" to it.
Target File: Dext.Net.RestClient.pas
- Modify
TDextHttpMethodenum:TDextHttpMethod = (hmGET, hmPOST, hmPUT, hmDELETE, hmPATCH, hmHEAD, hmOPTIONS, hmQUERY); - Modify the string mapping helper to translate
hmQUERYto'QUERY'and vice-versa:hmQUERY: MethodStr := 'QUERY';
Target File: Dext.Http.Executor.pas
- Modify
THttpExecutor.MethodToEnumto handle the'QUERY'method string.
3.2 Server-Side Routing & Request Pipeline
We will expose mapping methods for QUERY across all application builders.
Target File: Dext.Web.Interfaces.pas
- Add
MapQuerytoIApplicationBuilder:function MapQuery(const Path: string; Handler: TStaticHandler): IApplicationBuilder;
Target File: Dext.Web.Builder.pas
- Implement
MapQueryonTApplicationBuilder:function TApplicationBuilder.MapQuery(const Path: string; Handler: TStaticHandler): IApplicationBuilder; begin Result := MapEndpoint('QUERY', Path, Handler); end;
Target File: Dext.Web.pas
- Extend
THttpAppBuilderHelperhelper with fluent overloads forMapQueryand generic variations (MapQuery<T>,MapQuery<T, TResult>, etc.).
Target File: Dext.Web.ApplicationBuilder.Extensions.pas
- Implement
TApplicationBuilderExtensions.MapQuerystatic variations.
Target File: Dext.Web.ModelBinding.Extensions.pas
- Implement
MapQuery<T>inTApplicationBuilderWithModelBinding.
3.3 Accept-Query Header Negotiation
To declare which media types are supported for QUERY requests at a given endpoint, Dext will provide a metadata attribute and fluent configuration to automatically append the Accept-Query header on options requests:
App.MapQuery('/search', SearchHandler)
.AcceptsQuery('application/jsonpath', 'application/sql');
For endpoints mapped with MapQuery, an implicit OPTIONS handler response will automatically include QUERY in the Allow header and the registered query content-types in the Accept-Query header.
3.4 Caching of QUERY Responses
Because QUERY is safe and idempotent, responses are cacheable. However, unlike GET requests where the URL is the unique cache key, the cache key for QUERY must be constructed using both the Request URI and the hash of the Request Body.
- When a query response is marked cacheable (e.g. via
Response.Headers.Add('Cache-Control', ...)), the caching middleware must calculate a hash of the request body. - The cache key will be generated using a zero-allocation hashing mechanism (e.g., xxHash or MurmurHash3) over the request body bytes.
- Key format:
dext:cache:query:[MethodHash]:[URIHash]:[BodyHash].
4. Performance & Design Constraints
4.1 Strict Style Rules
To maintain consistency with the Dext codebase, the following coding guidelines must be strictly enforced:
- No inline variables: Declare variables inside the
varblock of the function/procedure, never inline. - No local variable prefixes: Do not prefix local variables with the
Lprefix (e.g., usebodyStreaminstead ofLBodyStream). - Loop counter: If a loop counter variable is named
I, it must be written in lowercasei(e.g.,for i := 0 to count - 1 do).
4.2 High-Performance & Zero-Allocation on Heap
- Use
TSpan<Char>andTSpan<Byte>: For parsing request headers, method strings, and hashing request body streams, prefer raw stack-allocated memory orTSpanslices. - String comparison bottlenecks: Use case-insensitive methods operating directly on spans to parse the request method. Avoid constructing intermediate strings.
- Dext Collections: Never use
System.Generics.Collectionsclasses (likeTList<T>orTDictionary<K,V>). Always utilize optimized customDext Collections(such asTDextList<T>or custom maps).
5. Verification Plan
Automated Tests
- Create a new unit test suite:
WebFrameworkTests.Tests.QueryMethod.pasin the Web.FrameworkTests project using the native Dext testing library. - Assert that
QUERYrequests can be sent viaTRestClientand successfully routed byTApplicationBuilder. - Assert that the
Accept-Queryheader is present when querying usingOPTIONS. - Test that model binding successfully extracts data from the body of a
QUERYrequest. - Assert that the Cache middleware constructs correct keys for identical query URIs but different request bodies.
Manual Verification
- Run the benchmark suite to ensure that introducing the
QUERYmethod parser insideTHttpExecutordoes not introduce any performance regression for existingGET/POSTrequests.