5 min read

The HTTP QUERY Method Comes to Laravel 13.19

Laravel 13.19 adds Http::query() and query/queryJson test helpers for the HTTP QUERY verb, a safe method that carries its parameters in the body.

Featured image for "The HTTP QUERY Method Comes to Laravel 13.19"

Every PHP developer who has built a search endpoint has run into the same awkward choice. A search is a read, so it feels like it belongs on GET. But the filters you want to send are a nested structure, and cramming a nested structure into a query string is ugly at best and broken at worst. So you reach for POST instead, and now your read operation is sitting on a verb that implies you are changing something. Caches will not touch it, and anyone reading your API contract has to know by convention that this particular POST does not mutate anything.

Laravel 13.19.0, released on July 8, 2026, adds first-class support for the HTTP method that was designed to solve exactly this problem: QUERY. The release adds an Http::query() client method and a pair of query() and queryJson() testing helpers, so you can both send QUERY requests and test routes that respond to them.

What the QUERY method actually is

QUERY is a new HTTP method being standardized by the IETF in the draft “The HTTP QUERY Method” (formally draft-ietf-httpbis-safe-method-w-body). The idea is simple once you see it. QUERY is a request method that is both safe and idempotent, exactly like GET, but it is allowed to carry a request body.

That combination is the important part. GET is safe and idempotent, but the specification discourages giving it a meaningful body, and plenty of intermediaries strip or ignore one. POST can carry any body you like, but it is neither safe nor idempotent, so nothing in the stack is allowed to assume it can be cached or retried. QUERY sits in the gap. You ask the server to run a query, described by the request content, over some data scoped to the target URI, and because the method is marked safe, caches and proxies can treat the response the way they would treat a GET.

The draft is explicit that the response to a QUERY is not assumed to be a representation of the resource at the target URI. You are not fetching the thing at that URL, you are asking it to perform a search and hand back the results. That is a much more honest description of what a search endpoint does than either GET or POST gives you.

Sending a QUERY request from Laravel

The new client method mirrors the shape of post(), put(), and patch(). It sends JSON by default, and it puts the payload in the request body rather than the URL.

use Illuminate\Support\Facades\Http;

$response = Http::query('https://api.example.com/search', [
    'filter' => ['status' => 'active'],
]);

If the service you are calling expects form-encoded data instead of JSON, chain asForm() the same way you already do with the other body-carrying verbs.

$response = Http::query('https://api.example.com/search', [
    'filter' => ['status' => 'active'],
])->asForm();

Notice that the nested filter array travels cleanly in the body. There is no filter[status]=active bracket encoding to build and no question of how deep a query string is allowed to nest. Your existing URL query handling is untouched, by the way. withQueryParameters() and the $query argument on get() behave exactly as they did before, so nothing you have already written changes.

Testing a route that responds to QUERY

The other half of the release is the testing side. Laravel added query() and queryJson() helpers that place the test payload in the request body, mirroring verb-specific helpers you already use like delete() and deleteJson().

Route::match(['QUERY'], '/search', fn () => request()->input('filter'));

$this->queryJson('/search', ['filter' => 'active'])
    ->assertOk();

The Route::match(['QUERY'], ...) line is worth pausing on. Because the router already accepts an arbitrary list of methods, you register a QUERY route the same way you would register any other. Point it at a controller that reads the body, runs your search, and returns the results, and you have an endpoint that is finally sitting on a verb that matches its behavior.

Should you adopt it today?

Here is the honest caveat. QUERY is still an IETF draft, not a ratified standard, and support across browsers, proxies, and API gateways is uneven. You would not want to rip out a working public GET or POST search endpoint and replace it tomorrow. For a browser-facing form, GET with query parameters is still the pragmatic default.

Where this shines right now is server-to-server communication, where you control both ends. If you are building an internal search service at a shop like PHP Architect and calling it from another PHP service, you can use QUERY today, send your nested filters in a clean JSON body, and keep the semantic promise that the call is safe and idempotent. That is a real improvement over the POST-that-does-not-mutate pattern most internal search APIs have been stuck with for years.

The rest of the release

The QUERY support is the headline, but 13.19.0 shipped a few other niceties worth a quick mention. There is a new reduceInto() collection method for when you mutate an accumulator in place rather than returning a new value each iteration, which reads much more cleanly for object accumulators like a stats object. There is a counted() string helper on Str and Stringable that pluralizes a word and prepends the count in one call, so str('order')->counted(2) gives you "2 orders". On the queue side, bulk SQS dispatches now go out through the SendMessageBatch API instead of one call per job, which meaningfully cuts request counts when you push many jobs at once, and the queue fake can now inspect reserved jobs for more precise test assertions.

None of those will change how you architect an application, but they are the kind of small, sharp additions that make the framework a little more pleasant every week. The QUERY method support, though, is the one to file away. It is a small API surface today, but it lines Laravel up with a piece of HTTP that is going to matter more as the standard firms up.

Sources