Digging Deeper

Precognition

Validate a request live from a form with Laravel Precognition, after the authorization checks and without running the endpoint.

Laravel Rest API supports Laravel Precognition. A precognitive request is authorized and validated like the real one, then stops before the endpoint runs: a form can show its errors as the user types.

Enabling Precognition

Precognition is off by default. Turn it on in config/rest.php:

'precognition' => [
    'enabled' => true,
],

Every route that Rest::resource() registers then gets Laravel's HandlePrecognitiveRequests middleware. The value is read when the routes are registered.

Sending a precognitive request

POST /api/products/search
Precognition: true
Content-Type: application/json

{"search": {"limit": 10, "filters": [{"field": "name", "value": "Desk lamp"}]}}
  • A valid request answers 204 No Content, with the Precognition-Success: true header.
  • An invalid request answers 422 with the errors, as the real request would.
  • The checks before validation still run: a denied check answers 403 first. See Policies.
  • Nothing is written, no event runs, and neither an action nor a write asks for a confirmation. Keys outside the perimeter still dispatch KeysOutOfReach when the request validates them.

Validating some keys only

Precognition-Validate-Only names the keys to validate, separated by commas. A name also covers the keys under it:

POST /api/products/search
Precognition: true
Precognition-Validate-Only: search.filters

{"search": {"limit": 7, "filters": [{"field": "name", "value": "Desk lamp"}]}}

This request answers 204: search.limit, which is not a page size of the resource, sits outside search.filters. With Precognition-Validate-Only: search, it answers:

{"message": "The selected search.limit is invalid.", "errors": {"search.limit": ["The selected search.limit is invalid."]}}

Errors that block a name

A name also reports the errors that stop its own validation, so a key never answers 204 while the real request fails above it:

  • the errors of each key above the name, such as search.filters and search.filters.0 for search.filters.0.field;
  • the errors of the keys that decide the rules of an entry above the name.
NameAlso reports
an attribute of a mutate entry, mutate.0.attributes.titleoperation, and key when the operation takes one
a key of a filter, search.filters.0.valuefield and operator
a key under an include, an aggregate or a relation grouprelation, and type for an aggregate
a key under a scope or an instructionname
a key of a sortfield
a field of an action or an instruction, fields.statusthe name of the entry that sets it, fields.0.name
a key under a MorphTo entrytype

For example, a filter on an unknown field reports the field to a name that targets its value:

Precognition-Validate-Only: search.filters.0.value

{"search": {"filters": [{"field": "stock", "value": 3}]}}
{"message": "The selected search.filters.0.field is invalid.", "errors": {"search.filters.0.field": ["The selected search.filters.0.field is invalid."]}}

A list over its limit reports on its own key, also to a name below it. With limits.sizes.filters set to 2, three filters and the name search.filters.0.field give:

{"message": "The search.filters field must not have more than 2 items.", "errors": {"search.filters": ["The search.filters field must not have more than 2 items."]}}

The other keys beside these stay out: search.filters.0.value does not report an error of search.filters.1.value or search.limit.

Key queries

The keys of mutate and resources are checked with database queries. A Precognition-Validate-Only request runs a key query only for the key it names, and for the key of an entry above a name, such as mutate.0.key for mutate.0.attributes.title. A request that leaves resources out runs no key query.