What Is the HTTP QUERY Method?
The HTTP QUERY method (RFC 10008) is a safe, cacheable HTTP verb designed specifically for queries. Like GET, it signals a read-only operation—but it carries its parameters in the request body, avoiding URL length limits and keeping sensitive values out of access logs and browser history.
Laravel 13.19 added Http::query() to the HTTP client and queryJson() / query() testing helpers. A first-class Route::query() helper is already merged for Laravel 14, but you can use Route::match() today to register QUERY routes in Laravel 13.
Setting Up Scout
Start from a fresh Laravel 13 app and install the API routes file and Scout:
php artisan install:api
composer require laravel/scout
Set the database driver in .env—no external search service required:
SCOUT_DRIVER=database
Create an Article model with migration and factory:
php artisan make:model Article -mf
Add the Searchable trait and define toSearchableArray():
use Laravel\Scout\Searchable;
class Article extends Model
{
use HasFactory, Searchable;
protected $fillable = ['title', 'body'];
public function toSearchableArray(): array
{
return ['title' => $this->title, 'body' => $this->body];
}
}
Defining a QUERY Route
In routes/api.php, register the route with Route::match():
Route::match(['QUERY'], '/articles/search', function (Request $request) {
$validated = $request->validate([
'search' => ['required', 'string'],
'per_page' => ['sometimes', 'integer', 'between:1,50'],
]);
return Article::search($validated['search'])
->paginate($validated['per_page'] ?? 15);
});
Validation and $request->input() read from the JSON body exactly as they would for a POST request. Running php artisan route:list confirms the verb:
QUERY api/articles/search
A raw request looks like this:
QUERY /api/articles/search HTTP/1.1
Content-Type: application/json
Accept: application/json
{"search": "scout", "per_page": 10}
Testing the Endpoint
Laravel 13.19's queryJson() helper makes tests feel identical to postJson():
$this->queryJson('/api/articles/search', ['search' => 'scout'])
->assertOk()
->assertJsonCount(1, 'data')
->assertJsonPath('data.0.title', 'Getting Started With Laravel Scout');
On the client side, use Http::query():
$response = Http::acceptJson()->query('https://example.com/api/articles/search', [
'search' => 'scout',
]);
CSRF and Web Routes
API routes skip CSRF automatically. For routes/web.php, Laravel 13's PreventRequestForgery middleware treats QUERY like POST and returns a 419. Extend the middleware to backport Laravel 14's behavior:
protected function isReading($request)
{
return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS', 'QUERY']);
}
Swap it in bootstrap/app.php and delete the override after upgrading to Laravel 14.
Gotchas Before You Ship
- PHP's built-in server returns
501 Not Implementedfor QUERY—use Herd, Valet, or test helpers instead. - CDNs, WAFs, and load balancers may block unrecognized verbs; test the full request path.
- CORS preflight is required for every cross-origin QUERY request—it is not a safelisted method.
- Caching is defined by the RFC but not yet implemented by browsers or CDNs.
- OpenAPI 3.2 added a first-class
queryoperation; toolchains targeting 3.0/3.1 cannot describe the endpoint yet.
Key Takeaways
Route::match(['QUERY'], ...)registers QUERY routes in Laravel 13 today.- Scout's database driver requires no external service and works out of the box.
queryJson()in Laravel 13.19 makes feature-testing QUERY endpoints straightforward.- Laravel 14 will add
Route::query()and exempt QUERY from CSRF automatically. - QUERY is best suited to internal APIs where you control both client and server.
Source: Build a Laravel Scout Search Endpoint With the HTTP QUERY Method