Mittelstand Radar : Signaux d'achat du Mittelstand allemand — réservez dès maintenant votre première édition du rapport.Rejoindre la liste d'attente
Une requête HTTP utilisant le verbe QUERY transporte un corps JSON vers un serveur, à côté du logo .NET et d'icônes pour la mise en cache et la répétabilité
Retour au blog
HTTP.NETASP.NET Core

La nouvelle méthode HTTP QUERY – et comment l'utiliser dès aujourd'hui avec .NET 10

Sascha KieferDéveloppement

La recherche en GET finit par faire exploser l'URL ; la recherche en POST n'est ni safe, ni idempotente, ni cachable. La nouvelle méthode HTTP QUERY (RFC 10008) comble précisément ce vide : un corps de requête comme POST, mais avec les garanties de GET. Nous voyons le problème que QUERY résout, ce que sa sémantique signifie en détail, et comment .NET 10 la prend déjà en charge côté client et côté serveur.

Chaque API REST finit par se heurter au même mur : vous construisez un endpoint de recherche censé accepter des filtres, un tri, de la pagination et quelques conditions imbriquées – et soudain, plus rien ne tient proprement dans une URL.

Il vous reste exactement deux mauvaises options. Soit vous entassez tout dans la query string d'une requête GET et vous finissez par buter contre les limites de longueur, l'enfer de l'encodage et le fait que des structures imbriquées comme ?filter[and][0][price][lt]=30 ne sont plus lisibles que par des machines. Soit vous transformez la recherche en POST – et vous abandonnez en silence tout ce qui fait une recherche : elle est safe, idempotente et cachable.

Une nouvelle méthode HTTP comble précisément ce vide : QUERY. Depuis juin 2026, elle est officiellement un Proposed Standard, publié sous le nom de RFC 10008 – et le meilleur : avec .NET 10, vous pouvez l'utiliser dès aujourd'hui.

Le problème : la recherche n'a jamais vraiment trouvé sa place dans HTTP

Voyons pourquoi aucune des méthodes existantes n'est idéale.

GET avec query string. Correct sur le plan sémantique – safe, idempotent, cachable. Mais les URL ont des limites en pratique : proxies, serveurs et navigateurs les coupent souvent à quelques kilo-octets. Les filtres complexes avec tableaux et conditions imbriquées ne se laissent encoder qu'à grand-peine et de façon illisible.

GET avec un corps. Tentant, mais c'est un champ de mines. HTTP ne définit aucune sémantique pour un corps sur GET, et – citation de la spécification – « diverses implémentations de clients, proxies et serveurs web traitent les requêtes GET avec corps différemment ». Certaines ignorent le corps, d'autres rejettent la requête. Inutilisable en pratique.

POST comme recherche. Le classique pragmatique. Vous pouvez envoyer des corps arbitraires, tout fonctionne – mais POST est par définition ni safe ni idempotent. Pour une recherche, cela signifie concrètement :

  • Pas de retries automatiques : un proxy ou une bibliothèque HTTP ne doit pas simplement renvoyer un POST après une coupure de connexion – il aurait pu modifier quelque chose.
  • Pas de mise en cache : les réponses POST ne sont pas mises en cache par défaut.
  • Mauvaise sémantique : POST signale « je modifie l'état côté serveur ». Pour une simple recherche, c'est tout bonnement faux.

La solution : QUERY

QUERY combine le meilleur des deux mondes. La spécification le résume clairement :

Un QUERY demande que la cible de la requête traite le contenu inclus de manière safe et idempotente, puis réponde avec le résultat de ce traitement.

Autrement dit : QUERY transporte sa requête dans le corps – comme POST, avec un contenu arbitraire et un Content-Type de votre choix. En même temps, la méthode garantit les mêmes propriétés que GET :

PropriétéGETQUERYPOST
Safe
Idempotent
Corps à sémantique définie
Réponse cachableseulement explicitement

Une requête QUERY brute ressemble à peu près à ceci :

QUERY /products/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json

{
  "category": "books",
  "price": { "lt": 30 },
  "sort": ["-published", "title"],
  "page": { "size": 20, "cursor": "eyJpZCI6NDJ9" }
}

Le serveur répond par 200 OK avec le résultat de la recherche dans le corps. Comme la méthode est safe et idempotente, les intermédiaires peuvent réessayer la requête sans risque en cas de coupure et mettre la réponse en cache.

Quelques détails qui comptent

  • Content-Type est obligatoire. Le serveur doit rejeter la requête si le Content-Type est absent ou incohérent avec le contenu. Le type de média définit le langage de requête – cela peut être du JSON, mais tout aussi bien application/sql, application/graphql ou un format de filtre maison.
  • Content-Location dans la réponse. Si le serveur répond avec un en-tête Content-Location, celui-ci pointe vers une ressource correspondant au résultat. Les clients peuvent ensuite récupérer cette URL via GET – matérialisant de fait une recherche en une ressource de résultat cachable.
  • Des codes d'erreur cohérents. Content-Type manquant → 400. Type de média non pris en charge → 415. Requête syntaxiquement valide mais non traitable → 422. Format de réponse demandé non pris en charge → 406.

Qui se cache derrière ce standard ?

QUERY provient de l'IETF HTTP Working Group (httpbis). La RFC 10008 a été rédigée par Julian Reschke, James M. Snell (Cloudflare) et Mike Bishop (Akamai) – la participation de fournisseurs de CDN et d'edge n'est pas un hasard, car ce sont précisément ces acteurs qui profitent des requêtes de recherche cachables. Pendant son développement, la méthode portait le titre de travail draft-ietf-httpbis-safe-method-w-body.

Quel est le niveau d'adoption ?

Honnêtement : la sémantique est standardisée, la pile ne l'est pas encore.

  • Les navigateurs ne peuvent actuellement pas envoyer de QUERY depuis fetch/XHR.
  • Les proxies et CDN ne mettent pas encore en cache les réponses QUERY de façon fiable à grande échelle – même si la présence de Cloudflare et Akamai parmi les auteurs indique la direction.
  • Les frameworks commencent tout juste à reconnaître la méthode.

Et c'est précisément là que .NET entre en jeu : .NET 10 (LTS, sorti en novembre 2025) fait partie des premières plateformes à offrir une prise en charge native de QUERY – côté client et côté serveur.

QUERY avec .NET 10 : côté client

Côté client, System.Net.Http a gagné une nouvelle propriété : HttpMethod.Query. Fini la chaîne magique, simplement :

using System.Net.Http.Json;

var filter = new ProductFilter("books", MaxPrice: 30);

using var request = new HttpRequestMessage(HttpMethod.Query, "https://api.example.com/products/search")
{
    Content = JsonContent.Create(filter)
};

using var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();

var page = await response.Content.ReadFromJsonAsync<ProductPage>();

C'est tout. HttpClient envoie la méthode QUERY avec son corps sur le réseau – et comme .NET sait que la méthode est idempotente, les mécanismes de résilience habituels (par exemple les retries automatiques via Microsoft.Extensions.Http.Resilience) s'activent exactement comme vous l'attendriez d'un GET.

QUERY avec .NET 10 : côté serveur

Dans ASP.NET Core 10, QUERY est disponible via deux nouveaux blocs dans Microsoft.AspNetCore.Http.HttpMethods :

public static readonly string Query = "QUERY";
public static bool IsQuery(string method);

Kestrel parse déjà la méthode et l'expose sous la forme "QUERY". Vous pouvez ainsi enregistrer un endpoint dans une minimal API – via le MapMethods générique :

app.MapMethods("/products/search", new[] { HttpMethods.Query },
    async (HttpContext ctx, ICatalog catalog) =>
    {
        var filter = await ctx.Request.ReadFromJsonAsync<ProductFilter>();
        if (filter is null)
            return Results.BadRequest();

        var page = await catalog.SearchAsync(filter);
        return Results.Ok(page);
    });

Un petit bémol – et le contournement

La proposition initiale pour ASP.NET Core incluait des helpers pratiques comme MapQuery(...) et un attribut [HttpQuery] pour les contrôleurs MVC. Après la revue d'API, ils ont toutefois été délibérément retirés de la release – dans .NET 10, il n'y a pas de MapQuery ni de [HttpQuery]. Seules les primitives ont été livrées.

Peu importe – le manque se comble en quelques lignes :

public static class QueryEndpointExtensions
{
    public static RouteHandlerBuilder MapQuery(
        this IEndpointRouteBuilder endpoints,
        string pattern,
        Delegate handler)
        => endpoints.MapMethods(pattern, new[] { HttpMethods.Query }, handler);
}

Votre endpoint redevient ainsi aussi lisible qu'on l'attendrait :

app.MapQuery("/products/search", async (ProductFilter filter, ICatalog catalog) =>
    Results.Ok(await catalog.SearchAsync(filter)));

Et si vous voulez aiguiller sur la méthode dans un middleware ou un handler existant :

if (HttpMethods.IsQuery(context.Request.Method))
{
    // Traitement spécifique à QUERY
}

Ce qu'il faut savoir d'autre

ASP.NET Core 10 reconnaît aussi QUERY dans la génération OpenAPI : comme OpenAPI 3.1 ne connaît pas (encore) la méthode, les endpoints QUERY sont proprement exclus lors de la génération du document, au lieu de provoquer une erreur. Si votre API repose fortement sur une spécification OpenAPI, gardez-le en tête – les endpoints fonctionnent, mais n'apparaissent pas (encore) dans le schéma généré.

Devrais-je déjà l'utiliser ?

Cela dépend de qui se trouve en face.

  • Serveur à serveur, les deux côtés sous votre contrôle (par ex. .NET ↔ .NET) : ici, vous pouvez utiliser QUERY de façon pertinente dès aujourd'hui. Client et serveur parlent la méthode, la sémantique colle, et vous gagnez des retries propres et une sémantique correcte gratuitement.
  • API publique avec clients navigateur : pas encore. Tant que fetch ne peut pas envoyer de QUERY, il vous faudra de toute façon un repli en POST – le double effort se justifie alors rarement.
  • Ne comptez pas encore sur la mise en cache par les intermédiaires. La sémantique l'autorise, mais proxies et CDN ne l'implémentent pas largement. Considérez-le comme un bonus agréable pour plus tard, pas comme une base d'architecture pour aujourd'hui.

Le juste milieu pragmatique : concevez déjà vos endpoints pour QUERY en interne (les quelques lignes du helper MapQuery ne coûtent rien), tout en proposant POST en parallèle pour les clients publics dans un premier temps. Vous serez ainsi prêt quand le reste de la pile rattrapera son retard.

Conclusion

QUERY fait partie de ces standardisations qui résolvent un problème auquel pratiquement chaque équipe d'API s'est déjà confrontée – la recherche qui ne tient pas dans une URL et pour laquelle POST est sémantiquement faux. La méthode vous donne le corps de POST avec les garanties de GET : safe, idempotente, cachable.

Avec la RFC 10008, la sémantique est figée, et .NET 10 fait partie des premières plateformes à la livrer – HttpMethod.Query côté client, HttpMethods.Query et HttpMethods.IsQuery côté serveur. Les navigateurs et les CDN ont encore besoin de temps, mais pour la communication de service à service dans le monde .NET, vous pouvez utiliser QUERY proprement dès aujourd'hui. Et avec un minuscule helper d'extension, cela se lit comme si le framework avait livré MapQuery dès le premier jour.


Besoin d'aide ?

Construisez-vous des API qui doivent faire plus que de simples endpoints CRUD – recherches complexes, sémantique HTTP propre, communication de services résiliente ? Nous aidons les équipes à rendre leurs interfaces .NET pérennes : du choix de la bonne méthode aux stratégies de cache, en passant par des patterns de retry et de résilience robustes. Contactez-nous simplement via notre page de contact – nous mettons vos API au niveau de l'état de l'art.