HTTP QUERY Method in .NET 10 and Angular
A practical guide to the HTTP QUERY method (RFC 10008), with GET vs POST vs QUERY comparisons, performance implications, and .NET 10 plus Angular examples.

Intro
For years, API teams had to choose between GET and POST even when neither method fit complex read-only queries particularly well. GET is safe and cache-friendly, but large filters become awkward in the URI. POST accepts a request body, but it does not communicate safe, idempotent read semantics clearly.
The HTTP QUERY method, standardized in RFC 10008, closes that gap. It allows structured request bodies for read-only operations while preserving the semantics developers expect from safe retrieval requests.
What Is the HTTP QUERY Method?
QUERY is an HTTP method for server-side queries that do not mutate resource state. It is designed for cases where clients need expressive request bodies, but the operation is still logically a read.
In practical terms, QUERY gives you:
- safe semantics like
GET - a request body like
POST - support for caching and retries without implying write behavior
That makes it a strong fit for search, reporting, analytics, and advanced filtering endpoints.
Why QUERY Matters
Before QUERY, developers usually had two imperfect options:
- put complex filters into query-string parameters and fight URI length, encoding, and readability limits
- send a
POSTbody to a search endpoint and accept that the method no longer advertises safe retrieval behavior
QUERY fixes that mismatch. It lets the transport contract match the business intent: a rich query that is still only a read.
GET vs POST vs QUERY
The simplest way to understand QUERY is to compare it directly with GET and POST.
| Feature | GET | POST | QUERY |
|---|---|---|---|
| Safe | ✅ Yes | ❌ Not guaranteed | ✅ Yes |
| Idempotent | ✅ Yes | ❌ Not guaranteed | ✅ Yes |
| Request body | 🚫 No defined semantics | ✅ Yes | ✅ Yes |
| Caching | ✅ Simple | ⚠️ Usually only useful for follow-up GET or HEAD | ✅ Supported |
| Retries | ✅ Safe | ⚠️ Risk of duplicate side effects | ✅ Safe |
| URI handling | Query params only | No URI query semantics | ✅ Body-based queries, optional URI for query or result |
QUERY combines the safety of GET with the flexibility of POST. That is the real value proposition.
Performance and Practical Benefits
1. Reduced URI bloat
Large filter objects, field selections, sorting rules, and nested conditions fit naturally in a JSON body. This avoids excessively long URIs and reduces the need for awkward parameter encoding conventions.
2. Improved caching efficiency
With QUERY, caches and intermediaries can treat the operation as safe. That creates room for more deliberate caching strategies than a POST-based search endpoint typically allows.
3. Automatic retries
Because QUERY is safe and idempotent, clients, gateways, and proxies can retry failed requests with much lower risk than retrying POST calls that may trigger side effects.
4. Security advantage
Sensitive filter payloads do not have to live in the URI, where they are more likely to appear in browser history, logs, monitoring dashboards, and intermediary tooling.
5. Better developer ergonomics
Developers can model queries as typed request objects instead of flattening them into string parameters. That improves readability, validation, reuse, and testability across backend and frontend code.
Making Use of QUERY in .NET 10
In ASP.NET Core, you can model QUERY similarly to the built-in verb attributes by defining a small custom attribute that maps the HTTP method explicitly.
using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Routing;
public sealed class HttpQueryAttribute : HttpMethodAttribute{ private static readonly IEnumerable<string> SupportedMethods = ["QUERY"];
public HttpQueryAttribute() : base(SupportedMethods) { }
public HttpQueryAttribute(string template) : base(SupportedMethods, template) { ArgumentNullException.ThrowIfNull(template); }}
public sealed record ContactQuery( string[] Select, string? Search, string? SortBy, int Limit = 10, int Offset = 0);
[ApiController][Route("api/[controller]")]public sealed class ContactsController : ControllerBase{ private readonly ContactService _contactService;
public ContactsController(ContactService contactService) { _contactService = contactService; }
[HttpQuery("search")] public IActionResult QueryContacts([FromBody] ContactQuery query) { var results = _contactService.Search(query);
Response.Headers.ETag = $"W/\"contacts-{query.GetHashCode()}\""; Response.Headers.CacheControl = "public, max-age=60";
return Ok(results); }}Why this pattern works:
HttpQueryAttributeis analogous toHttpGetAttributeorHttpPostAttribute- the body carries structured query data cleanly
- the endpoint contract makes it obvious that the operation is read-only
- infrastructure can reason more safely about retries and cacheability
If you prefer minimal APIs, you can also expose QUERY by mapping an endpoint and constraining the accepted method metadata to QUERY.
Making Use of QUERY in Angular
Angular’s HttpClient already exposes a generic request method, which makes custom HTTP verbs straightforward.
this.http.request('QUERY', '/api/contacts/search', { body: { select: ['surname', 'email'], search: 'smith', sortBy: 'surname', limit: 10, offset: 0, }, headers: { 'Content-Type': 'application/json', },}).subscribe(result => { console.log(result);});This is especially useful when frontend screens need:
- advanced search or filter builders
- dynamic analytics requests
- reusable typed query objects
- safe retry behavior on unreliable networks
In other words, Angular does not need a special library feature to benefit from QUERY; the generic request pipeline is already enough.
Use Cases Where QUERY Shines
- Search APIs with complex filters, pagination, field selection, and sorting
- Analytics dashboards that send large JSONPath, aggregation, or SQL-like request bodies
- Data-heavy applications that want to avoid very long query strings
- Retry-heavy environments such as mobile apps and unstable networks
- Internal enterprise APIs where request objects are versioned and validated centrally
Caching and Retry Considerations
QUERY does not mean every response should be cached forever. It means the method semantics make caching and retries far safer to reason about than POST.
Good practices include:
- defining explicit cache headers for predictable result windows
- generating stable cache keys from normalized query bodies
- using
ETagor equivalent validators when result sets are expensive to compute - treating retries as safe only when the endpoint truly remains side-effect free
That last point matters. A method is only as safe as its implementation. If your QUERY endpoint writes audit rows, mutates state, or triggers background work, you have already broken the contract.
Sequence Diagram
The following flow shows why QUERY is attractive for modern client-server interactions.
sequenceDiagram participant UI as Angular Client participant API as ASP.NET Core API participant Cache as HTTP Cache participant Data as Query Service
UI->>API: QUERY /api/contacts/search\n{ select, search, sortBy, limit } API->>Data: Execute read-only query Data-->>API: Matching contacts API->>Cache: Store cacheable response metadata API-->>UI: 200 OK + results + cache headers
Note over UI,API: Safe and idempotent semantics allow controlled retries UI->>API: Retry QUERY after transient network issue API-->>UI: Cached or recomputed read-only resultHow to Validate QUERY Endpoints
- confirm the endpoint performs no writes, background mutations, or side effects
- verify that identical request bodies produce equivalent results across retries
- test cache headers and conditional request behavior explicitly
- validate large filter payloads that would have been awkward as URI parameters
- document the query schema so backend and frontend teams share one contract
If you want a practical reference implementation, see my GitHub repo: AspNetQueryVerb.
Summary
The HTTP QUERY method is a meaningful improvement for API design. It bridges the gap between GET and POST, preserves safe read semantics, supports richer request payloads, and improves caching, retries, and developer ergonomics.
For .NET 10 and Angular teams, that means cleaner APIs for search and analytics scenarios without overloading GET or misusing POST.




