RFC 10008 ist da, und er schließt ein Loch, um das wir alle seit zwanzig Jahren herumlaufen. QUERY schickt seine Payload im Request-Body wie POST, ist aber als safe und idempotent deklariert wie GET, und damit dürfen Caches und Retry-Logik ihm vertrauen. Es bringt eine Discovery-Story mit – OPTIONS plus ein Accept-Query-Header, der dir sagt, welche Media Types der Endpunkt akzeptiert – und Location sowie Content-Location in der Response, damit ein Cache überhaupt etwas hat, worauf er keyen kann. Das ist ein sauberer, kleiner Entwurf. Meine Position: Fang jetzt an, das in deinen APIs zu unterstützen, mit POST-Fallback dahinter, denn die Spezifikation war noch nie der schwierige Teil. Der schwierige Teil ist jede Kiste zwischen deinem Client und deinem PHP-Prozess, und diese Kisten lernen neue Methoden nur dann, wenn jemand sie dazu zwingt.

Lass mich konkret werden bei dem Schmerz, den QUERY beenden soll, denn der ist alles andere als theoretisch. Du hast einen Such-Endpunkt. Das Filterobjekt ist eine verschachtelte Struktur mit fünfzehn Facetten, einer Bounding Box und einer Sort-Spec. Pack das in den Query String, und du bist eine gespeicherte Suche von einem 414 entfernt, deine Access Logs archivieren klammheimlich für immer Kunden-E-Mail-Adressen, und dein CDN behandelt jede Umsortierung derselben Parameter als anderen Cache Key, weshalb die Hit Rate bei fünfzehn Prozent klebt. Also schwenkst du auf POST. Jetzt ist die URL sauber und das Log ist sauber, aber du hast jedem Intermediary auf der Strecke gesagt, dass dieser Request vielleicht State ändert. Varnish cached ihn nicht. Dein HTTP-Client wiederholt ihn nicht bei einem Connection Reset, was bedeutet: Ein wackliges Upstream wird zum sichtbaren Fehler statt zu einem Schluckauf. Du hast das Problem nicht gelöst, du hast es gegen ein anderes getauscht und aufgehört, darüber nachzudenken.

Das ehrliche Gegenargument verdient mehr als ein Schulterzucken, also hier in voller Stärke. POST funktioniert. Überall, in jedem Proxy, in jeder Corporate-WAF, in jedem SDK, das deine Kunden längst gegen deine API geschrieben haben. Einen dritten Codepfad einzuziehen, damit ein Such-Request theoretisch cachebar wird, ist Churn – und die meisten Suchergebnisse sind ohnehin personalisiert, was Shared Caching killt, bevor QUERY überhaupt eine Chance bekommt. Browser helfen dir dabei auch nicht: Ein HTML-Formular kennt weiterhin nur GET oder POST, QUERY existiert also nur für fetch und Server-zu-Server-Verkehr. Und unbekannte Methoden sind der Ort, an dem Infrastruktur stirbt – ein ALB mit Method-Allowlist, eine WAF, deren Default Rule Set alles außerhalb der klassischen sieben verwirft, ein Corporate Proxy, der ein 501 ohne Body zurückgibt. Jedes davon ist ein echter Dienstagnachmittag, den du nicht zurückbekommst.

Ich lande trotzdem bei Adoption, und zwar aus einem Grund, der wenig mit Cache Hit Rates zu tun hat. QUERY lässt dich auf Protokollebene sagen, was du meinst. Aktuell lebt der Unterschied zwischen "dieses POST liest Daten" und "dieses POST belastet eine Kreditkarte" in einer README, einem Route-Namen und im Gedächtnis der Person, die den Client geschrieben hat. Nichts im Wire-Format unterscheidet die beiden, also muss jede generische Schicht – Retry-Middleware, Circuit Breaker, Request-Replay in deinem Debugging-Proxy, die Idempotenz-Logik in deiner Job Queue – vom gefährlichen Fall ausgehen. Semantik, die du nur in Prosa ausdrücken kannst, ist Semantik, die du nicht automatisieren kannst. QUERY macht aus einer Konvention eine Tatsache, auf die die Maschine reagieren kann, und das zahlt sich noch lange aus, wenn das Caching-Argument längst langweilig geworden ist.

Für die PHP-Seite ist die gute Nachricht: Dem größten Teil unseres Stacks ist es egal, was da als Method-String steht. PSR-7 und PSR-15 behandeln ihn als opakes Token, Guzzle schickt, was du ihm gibst, und dein Controller liest ohnehin php://input statt $_POST. Die Reibung sitzt an den konkreten Stellen, die die klassische Liste hardcoden: Symfonys HttpFoundation hat explizite Mengen dafür, welche Methoden als safe und cacheable gelten, Laravels Router validiert gegen bekannte Verben, und alles, was einen Request aus den Globals rekonstruiert, muss wissen, dass weder $_GET noch $_POST für dich befüllt werden. Nichts davon ist eine tiefe Operation, aber es ist die Art Arbeit, die nur passiert, wenn jemand das Issue aufmacht. Wenn du einen Router, einen HTTP-Client-Wrapper oder ein API-Skeleton pflegst: Das ist ein wirklich guter Wochenend-Beitrag – kleiner Diff, lange Haltbarkeit.

Das Muster, das ich dieses Quartal tatsächlich in Produktion schicken würde, ist unspektakulär und mit Absicht langweilig. Registriere denselben Handler für QUERY und POST auf deinen Such- und Report-Endpunkten. Antworte auf OPTIONS ehrlich mit den Methoden und den Accept-Query-Media-Types, die du unterstützt, damit ein Client einmal proben und die Antwort cachen kann. Auf der Client-Seite: QUERY versuchen, und bei einem 405 oder 501 für diesen Host auf POST zurückfallen und sich das merken – zahl den fehlgeschlagenen Round Trip nicht bei jedem Aufruf. Dann prüf deine Edge: ob nginx die Methode unangetastet an FastCGI weiterreicht, ob die Allowlist deines CDN sie enthält, ob die Default-Action deiner WAF für unbekannte Methoden Block oder Pass ist. Eine halbe Stunde curl gegen Staging sagt dir mehr über deinen realen Adoption-Zeitplan als jede Spec-Diskussion.

Was ich wirklich nicht weiß, ist, wo der Kipppunkt liegt. Niemand deployt QUERY-Support, solange keine Clients es schicken, und kein Client schickt es, solange keine Server es deployen, und beides passiert nicht, solange das CDN dazwischen mit 501 antwortet. Irgendwer muss sich zuerst bewegen, und zwar mit Verlust. Also: Wenn du heute eine öffentliche API betreibst – würdest du QUERY dieses Jahr neben POST aktivieren, oder wartest du, bis dein CDN-Anbieter Support in einem Changelog ankündigt? Und falls du es schon probiert hast: Welche Kiste in deinem Stack ist zuerst umgefallen?