Manikandan — Manikandan
Updated on 6 min read Manikandan API Design

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.

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 POST body 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.

FeatureGETPOSTQUERY
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 handlingQuery params onlyNo 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:

  • HttpQueryAttribute is analogous to HttpGetAttribute or HttpPostAttribute
  • 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 ETag or 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 result

How 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.

Share:
Back to Blog

Related Posts

View All Posts »