Ajaxify Your Laravel Application Automatically
You have a “nice little” Laravel app. You return views from your controllers, you redirect with a flash message when you’re done with something or when something goes wrong.
But sometimes you need to send Ajax requests to the server. And this time those views and redirects don’t make sense. You need JSON response. You create two different methods in your controller, one returns JSON and one returns View, because you also want the page to be loaded from server when user(or search engines) hit the url directly. And now things start to get messy.
What if you can write an HTTP Middleware which detects Ajax requests and converts responses to Ajax compatible responses? For example turn the response of this:
$user = ['name' => 'Usman', 'email' => '[email protected]'];
return View::make('user.show', $user);
into this
{"name": "Usman", "email": "[email protected]"}
or response of this
return Redirect::to('/')->with('error', 'User not found');
to this
{"error": "User not found"} // with a 301 header
That’d be great, right? All this can be automated, I will show you how.
Let’s Code
We’ll create an HTTP middleware by running php artisan make:middleware Ajaxify
Or just create the class manually in (app/Http/Middleware/
).
It’ll look like this:
namespace App\Http\Middleware;
use Closure;
class Ajaxify
{
public function handle($request, Closure $next)
{
return $next($request);
}
}
Handle Method
Here we basically use couple of helper methods, which we’ll create next.
We check if we really need to alter the original response or not. Then we check if the
response is successful (it has 20* status code) or not. If yes, we get all the the data
passed to our view and then return the data as JSON response. It’s the key thing here.
If the response is not successful, we get all the flash data. If we have them then we return the flash data as a JSON response.
public function handle($request, Closure $next, $guard = null)
{
// Get the original response
$response = $next($request);
if (! $this->shouldAjaxify($request, $response)) {
return $response;
}
// A 20* response
if ($response->isSuccessful()) {
$originalContent = $response->getOriginalContent();
// Get the data we passed to our view
$data = $originalContent->getData();
// Return the data passed to view as JSON response
return response()->json($data);
}
// We don't have a successful response,
// we rather have a redirect like response
$flashData = $this->getFlashData($request);
if (! count($flashData)) {
return $response;
}
// Return all the flash data as JSON
return response()->json($flashData, $response->getStatusCode());
}
Helper Methods
Now we’ll add couple of protected methods in the class. First one is to help us determine if we should convert the response to JSON response or not.
protected function shouldAjaxify($request, $response)
{
// If we already have a JSON response we don't need to do anything
if ($response instanceof JsonResponse) {
return false;
}
// If there is a server (status 50*) error, we won't do anything
if ($response->isServerError()) {
return false;
}
// It's not a View response
if ($response->isSuccessful() && ! method_exists($response->getOriginalContent(), 'getData')) {
return false;
}
// Now if it's an Ajax request or the clients wants a JSON response or we've
// a query string param 'ajaxify' then we'll Ajaxify, else we won't.
return $request->ajax() || $request->wantsJson() || $request->exists('ajaxify');
}
So this method basically determines if we need to alter the response or just ignore it.
Now another helper method to get all flash data from the session:
protected function getFlashData($request)
{
// Get all session data and convert the array to a Collection object
$sessionData = collect($request->session()->all());
// Filter only flash data from session data
$flashedKeys = $request->session()->get('flash.new');
$flashData = $sessionData->only($flashedKeys);
// Delete flash data, as we've already used them
$request->session()->forget($flashedKeys);
return $flashData;
}
Finally
Register our middleware as a global middleware, by going to this file app/Http/Kernel.php
.
in the web section we will add this:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\Ajaxify::class,
],
];
Now you can try sending an Ajax request to your existing route or just try this in your browser: http://yourapp.dev?ajaxify
Caution:
Do not pass sensitive data to your view or to flash session. It will expose all data.
Be careful when passing full model,
use $hidden and $visible
properties in your models to secure sensitive database fields.