6 min read

Using Laravel Precognition To Simplify Form Validations

Interested in generating passive income? Join our partnership program and receive a commission on each new client referral. Learn more.

Using Laravel precognition to simplify form validations

Laravel Precognition is a set of frontend tools closely integrated with Laravel Core to simplify form validations and execute endpoint logic separately from the controller. It intercepts the standard request execution flow, which means that instead of completing the full cycle, it stops just before reaching the controller. This feature is what makes Precognition useful for providing live validation in front-end applications.

While Laravel offers comfortable and powerful validation capabilities, it doesn’t cover all aspects of form validation. This is where Laravel Precognition comes into play. With Precognition, you can set up validation rules in the backend and apply them to validate forms on the frontend side as well.

Since we’ve used Laravel Precognition in several of our projects, we’ll delve deeper into real-life use cases and explore how Precognition really works, including insights into its frontend and backend libraries.

Laravel Precognition: How Does It Really Work?

Here I'll show you how it works

While building a large-scale project containing multiple forms, we had a case where we needed to verify the information provided by users, particularly the times they needed to attend certain events, such as classes or lessons. This required us to verify that these times were sorted correctly, which involved tasks such as parsing times, applying logic, and displaying errors appropriately.

If validations were done on the frontend, we’d still need to check data validity on the backend, which means writing the code twice and taking more time. This is where Precognition came to the rescue and helped us cut validation writing time in half.

When using Laravel Precognition, we had to rethink traditional single-page application (SPA) form submissions. In the traditional method, you can submit part of a form and rely on controller logic to recognize the first part submitted, like with multi-step forms.

However, Precognition does things a bit differently. With Precognition, submitting all fields is important, even if some might not be necessary. This helps ensure that the submission process is successfully completed.

You’ll receive validation errors if you only submit certain fields and other required fields are left out. Think of it like working with HTML forms: when updating a user profile, the entire form should still be submitted even if only a single detail changes.

So, let’s see how Precognitions works under the hood and how it handles requests:

Precognition settings

This is the request from Precognition’s frontend library. It adds headers to these requests, which are later used in the backend to figure out if the request is for Precognition or not. Now, let’s take a look at the backend part:

Precognition request

/**
* Handle an incoming request.
*
* @param  \Illuminate\Http\Request  $request
* @param  \Closure  $next
* @return \Illuminate\Http\Response
*/
public function handle($request, $next)
{
   if (! $request->isAttemptingPrecognition()) {
       return $this->appendVaryHeader($request, $next($request));
   }
   $this->prepareForPrecognition($request);
   return tap($next($request), function ($response) use ($request) {
       $response->headers->set('Precognition', 'true');
       $this->appendVaryHeader($request, $response);
   });
}
/**
* Prepare to handle a precognitive request.
*
* @param  \Illuminate\Http\Request  $request
* @return void
*/
protected function prepareForPrecognition($request)
{
   $request->attributes->set('precognitive', true);
   $this->container->bind(CallableDispatcherContract::class, fn ($app) => new PrecognitionCallableDispatcher($app));
   $this->container->bind(ControllerDispatcherContract::class, fn ($app) => new PrecognitionControllerDispatcher($app));
}

As you can see, it checks if the request requires precognitive handling and adds headers accordingly. This is something like a flag that will be used later to stop code execution before the controller.

Precognition comes with a front-end library that simplifies tasks. But, there are cases where customization is necessary. For example, you might need to send an object without forms or add extra headers to your request, which isn’t covered in the Laravel documentation. You can also manually add Precognition headers, but it’s time-consuming. For this, the Laravel team offers an undocumented client library at laravel-precognition/dist/client.js. If we inspect this file, we will see:

Precognition client

export const client = {
   get: (url, data = {}, config = {}) => request(mergeConfig('get', url, data, config)),
   post: (url, data = {}, config = {}) => request(mergeConfig('post', url, data, config)),
   patch: (url, data = {}, config = {}) => request(mergeConfig('patch', url, data, config)),
   put: (url, data = {}, config = {}) => request(mergeConfig('put', url, data, config)),
   delete: (url, data = {}, config = {}) => request(mergeConfig('delete', url, data, config)),
   use(axios) {
       axiosClient = axios;
       return client;
   },
   axios() {
       return axiosClient;
   },
   fingerprintRequestsUsing(callback) {
       requestFingerprintResolver = callback === null
           ? () => null
           : callback;
       return client;
   },
   determineSuccessUsing(callback) {
       successResolver = callback;
       return client;
   },
};

As you can see, you can still manually use precognitive requests and take advantage of juicy parts of Laravel Precognition. The headers will be managed automatically.

Laravel Precognition: Final Thoughts

To sum up, Precognition isn’t even a separate package; it’s included with Laravel by default. Activating and using is pretty straightforward. As described in the documentation, its use case is to “anticipate the outcome of a future HTTP request.” In simpler terms, it allows you to send a request and check for potential failure before reaching the controller. If it’s successful, it waits for the final form submission without executing further business logic.

Except for form validation, Laravel Precognition can be used in different other cases; a few examples include enabling auto-save functionality in content creation platforms, validating shopping carts in e-commerce, and previewing rate limits for APIs.

Meet the authors

We are a 200+ people agency and provide product design, software development, and creative growth marketing services to companies ranging from fresh startups to established enterprises. Our work has earned us 100+ international awards, partnerships with Laravel, Vue, Meta, and Google, and the title of Georgia’s agency of the year in 2019 and 2021.

Contact us