The package switches itself on when you install it. This page explains where it acts, what exactly it adds and how to apply it to a single route.
Where it acts
The scope is decided by three options of the configuration:
| Option | Effect |
|---|---|
mode | prefix (default): only routes that start with path_prefix. global: the whole application, 404 and 500 included |
path_prefix | The route prefix when mode is prefix (default api): a string or an array of strings |
except | Routes the package never touches, in any mode (default ['up']); wildcards allowed |
Outside that scope the package touches nothing: a route such as / answers as usual, with its HTML. Inside it, everything comes out as JSON:API, errors of a route that does not exist included.
What it adds
Inside the scope, the package adds only four middleware at the start of the HTTP kernel's global stack. They run before the route is looked up, so they also cover routes that do not exist, and before auth:
| Middleware | What it does |
|---|---|
json-api.apply | Marks the request as JSON:API and fixes the Accept so auth answers 401 instead of looking up the login route |
json-api.negotiate | Negotiates the content: it checks the Content-Type (415) and the Accept (406). The Content-Type is checked only when the request has a body and its method is POST, PATCH or DELETE (PUT only with allow_put) |
json-api.query | Validates the query parameters (400, with source.) |
json-api.document | Validates the body document (400 or 403, with source.) |
To know in what order everything is checked when a request fails for more than one reason, see The order of the checks.
You do not need to touch bootstrap/app.php, Kernel or Handler. If your bootstrap/app.php replaces the global list with withMiddleware (Laravel 11 to 13), the package middleware are added afterwards and end up at the start of the stack.
A single route outside the scope
If you need JSON:API on a route that falls outside the scope, apply all four middleware at once with json-api:
Route::get('reports/{report}', [ReportController::class, 'show'])->middleware('json-api');
The four also exist separately. There is also json-api.options, which sets the pagination limits of a route, for example json-api.options:per_page=25,max_per_page=50. And json-api.document:relationship or json-api.document:resource force the kind of document without looking at the URL.