La RFC 10008 est sortie, et elle bouche un trou qu'on contourne depuis vingt ans. QUERY envoie sa charge utile dans le corps de la requête comme POST, mais elle est déclarée sûre et idempotente comme GET, donc les caches et la logique de retry ont le droit de lui faire confiance. Elle vient avec un mécanisme de découverte — OPTIONS plus un en-tête Accept-Query qui t'indique quels types de médias l'endpoint accepte — et avec Location et Content-Location dans la réponse, pour qu'un cache ait de quoi construire sa clé. C'est un design propre et minimal. Ma position : commence à la supporter dans tes API dès maintenant, avec un repli sur POST, parce que la spécification n'a jamais été le point dur. Le point dur, c'est chaque boîtier entre ton client et ton processus PHP, et ces boîtiers n'apprennent de nouvelles méthodes que si quelqu'un les y force.

Soyons concrets sur la douleur que QUERY est censée faire disparaître, parce qu'elle n'a rien de théorique. Tu as un endpoint de recherche. L'objet de filtres est une structure imbriquée avec quinze facettes, une bounding box et une spec de tri. Mets-le dans la query string et tu es à une recherche sauvegardée d'un 414, tes logs d'accès archivent tranquillement les adresses e-mail de tes clients pour l'éternité, et ton CDN considère chaque réordonnancement des mêmes paramètres comme une clé de cache différente, donc le taux de hit stagne à quinze pour cent. Du coup tu passes en POST. L'URL est propre, les logs sont propres, mais tu viens d'annoncer à tous les intermédiaires du chemin que cette requête pourrait modifier un état. Varnish ne la mettra pas en cache. Ton client HTTP ne la rejouera pas après une connexion coupée, ce qui veut dire qu'un upstream capricieux devient une erreur visible par l'utilisateur au lieu d'un hoquet. Tu n'as pas résolu le problème ; tu l'as échangé contre un autre et tu as arrêté d'y penser.

Le contre-argument honnête mérite mieux qu'un haussement d'épaules, alors le voici dans sa version forte. POST fonctionne. Ça fonctionne partout, dans chaque proxy, dans chaque WAF d'entreprise, dans chaque SDK que tes clients ont déjà écrit contre ton API. Ajouter un troisième chemin de code pour qu'une requête de recherche soit théoriquement cacheable, c'est du churn, et de toute façon la plupart des résultats de recherche sont personnalisés, ce qui tue le cache partagé avant même que QUERY ait sa chance. Pendant ce temps, les navigateurs ne t'aideront pas : un formulaire HTML n'émet toujours que du GET ou du POST, donc QUERY n'existe que pour fetch et le trafic serveur à serveur. Et les méthodes inconnues, c'est le cimetière de l'infrastructure — un ALB avec une allowlist de méthodes, un WAF dont le jeu de règles par défaut jette tout ce qui sort des sept classiques, un proxy d'entreprise qui répond 501 sans corps. Chacun de ces cas est un vrai mardi après-midi que tu ne récupéreras pas.

J'atterris quand même sur l'adoption, pour une raison qui n'a pas grand-chose à voir avec les taux de hit. QUERY te permet de dire ce que tu veux dire au niveau du protocole. Aujourd'hui, la différence entre « ce POST lit des données » et « ce POST débite une carte bancaire » vit dans un README, un nom de route et la mémoire de celui qui a écrit le client. Rien dans le format sur le fil ne les distingue, donc chaque couche générique — middleware de retry, circuit breakers, rejeu de requête dans ton proxy de debug, la logique d'idempotence de ta file de jobs — doit supposer le cas dangereux. Une sémantique que tu ne peux exprimer qu'en prose est une sémantique que tu ne peux pas automatiser. QUERY transforme une convention en un fait sur lequel la machine peut agir, et ça capitalise longtemps après que l'argument du cache soit devenu ennuyeux.

Côté PHP, la bonne nouvelle c'est que l'essentiel de notre stack se fiche de la chaîne de la méthode. PSR-7 et PSR-15 la traitent comme un token opaque, Guzzle enverra ce que tu lui donnes, et ton contrôleur lit php://input plutôt que $_POST dans les deux cas. Le frottement se trouve aux endroits précis qui codent en dur la liste classique : HttpFoundation de Symfony a des ensembles explicites de méthodes considérées comme sûres et cacheables, le routeur de Laravel valide contre des verbes connus, et tout ce qui reconstruit une requête depuis les globales doit savoir que ni $_GET ni $_POST ne seront remplis pour toi. Rien de tout ça n'est de la chirurgie lourde, mais c'est le genre de boulot qui ne se fait que si quelqu'un ouvre l'issue. Si tu maintiens un routeur, un wrapper de client HTTP ou un squelette d'API, c'est une vraie bonne contribution de week-end — petit diff, longue durée de vie.

Le pattern que je mettrais réellement en production ce trimestre est peu glamour, et volontairement ennuyeux. Enregistre le même handler pour QUERY et POST sur tes endpoints de recherche et de rapports. Réponds honnêtement à OPTIONS avec les méthodes et les types de médias Accept-Query que tu supportes, pour qu'un client puisse sonder une fois et mettre la réponse en cache. Côté client, tente QUERY, et sur un 405 ou un 501 replie-toi sur POST pour cet hôte et mémorise le résultat — ne paie pas l'aller-retour raté à chaque appel. Ensuite, va inspecter ton edge : est-ce que nginx transmet la méthode à FastCGI sans y toucher, est-ce que l'allowlist de ton CDN l'inclut, est-ce que l'action par défaut de ton WAF pour une méthode inconnue est block ou pass. Une demi-heure de curl contre ton staging t'en dira plus sur ton vrai calendrier d'adoption que n'importe quelle discussion de spec.

Ce que je ne sais sincèrement pas, c'est où se situe le point de bascule. Personne ne déploie le support de QUERY tant que les clients ne l'envoient pas, aucun client ne l'envoie tant que les serveurs ne le déploient pas, et rien de tout ça n'arrive tant que le CDN au milieu répond 501. Quelqu'un doit bouger le premier à perte. Alors : si tu opères une API publique aujourd'hui, est-ce que tu activerais QUERY à côté de POST cette année, ou est-ce que tu attends que ton fournisseur de CDN annonce le support dans un changelog — et si tu as déjà essayé, quel boîtier de ta stack a cassé en premier ?