Build a Laravel Scout Search Endpoint With the HTTP QUERY Method
Laravel #Laravel #Laravel Scout #HTTP QUERY #REST API #PHP #Laravel 13

Build a Laravel Scout Search Endpoint With the HTTP QUERY Method

3 min read Mohamed Said Mohamed Said

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 Implemented for 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 query operation; 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

Found this useful?

Frequently Asked Questions

3 questions
Q01 Can I use the HTTP QUERY method in Laravel 13 before Route::query() is available?
Yes. Laravel 13's router accepts any HTTP verb via Route::match(). Register your route with Route::match(['QUERY'], '/path', $handler) and it works today. The dedicated Route::query() shorthand is coming in Laravel 14.
Q02 Why does PHP's built-in server return 501 for QUERY requests?
PHP's built-in server hard-codes the HTTP methods it accepts and does not recognize QUERY, so it returns 501 Not Implemented before the request reaches Laravel. Use Nginx-based environments like Laravel Herd or Valet, or rely on Laravel's HTTP testing helpers, which dispatch requests directly through the framework.
Q03 Do QUERY routes in routes/web.php require CSRF handling?
Yes, in Laravel 13 the PreventRequestForgery middleware treats QUERY like POST and will return a 419. You can extend the middleware to add QUERY to its list of read verbs, or exclude individual routes with withoutMiddleware(). Laravel 14 will exempt QUERY automatically.

Continue reading

More Articles

View all