Laravel: Convert all responses to JSON automatically

Because not every person in the world wants HTML, nor use in every freaking controller.

Italo Baeza Cabrera
3 min readJan 9, 2019

--

And it will be

If you are doing something like an API, a JSON response is almost mandatory. The problem lies when the client doesn’t issue a Request telling explicitly to your app that accepts JSON as a response. When that occurs, your app will nonchalantly send a HTML response, which is not cool.

The Middleware

Well, there is very simple way to “force” your app to return JSON, and that is with one line middleware. We will call it because indicates the response should be JSON, but doesn’t forces it.

<?php

namespace App\Http\Middleware;

use Closure;

class JsonMiddleware
{
/**
* Handle an incoming request.
*
*
@param \Illuminate\Http\Request $request
*
@param \Closure $next
*
@return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');

return $next($request);
}
}

What this does is modify the incoming request and set (or replace) the “Accept” header.

When the app is ready to send a Response, it will check if the Request wanted JSON, and this is done by looking if the header is or any other JSON-like header. So, the application will try to push a JSON response automatically, when possible.

The place

In our , we can find the list of middlewares the App manages.

Since we want this to run only in our API routes, we will register the middleware under the api group, along with throttler and bindings.

/**
* The application's route middleware groups.
*
*
@var array
*/
protected $middlewareGroups = [
'web' => [
// ...
],

'api' => [
'throttle:60,1',
'bindings',

// Our new JSON Middleware
\App\Http\Middleware\Api\JsonMiddleware::class,
],
];

If we need more control of where we can put it, we can register an alias like in the .

/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
*
@var array
*/
protected $routeMiddleware = [
// ...

// Register the alias for the JSON middleware
'return-json' => \App\Http\Middleware\Api\JsonMiddleware::class,
];

Then in our routes invoke the middleware where we need.

Route::namespace('User')
->middleware(['api', 'return-json']) // Use our JSON Middleware
->group(function () {
Route::get('user/profile', 'UserController@profile');
Route::get('user/calls', 'UserController@calls');
);

The Order

Laravel conveniently has a global order for middlewares. When they are called in a route, it will run them in the same order displayed on .

We want this to start first because is what the client should have set in the first place. This will allow, for example, to not return a redirect when the authentication fails since it doesn’t do it when it checks if the request should return JSON. Thanks to this order, the “Should return JSON” flag is set way before we hit the Authentication middleware condition.

/**
* The priority-sorted list of middleware.
*
* This forces the listed middleware to always be in the given order.
*
*
@var array
*/
protected $middlewarePriority = [
// Put the JSON Middleware first
\App\Http\Middleware\Api\JsonMiddleware::class,
// Then the rest...
];

And that’s it.

Bonus: Forcing a JSON Response

Additionally to our , we can ensure the response is a instance.

We will modify the middleware by calling the our app is using to create the response with automatic injection, and through it make the JSON response.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\JsonResponse;

class JsonMiddleware
{
/**
* The Response Factory our app uses
*
*
@var ResponseFactory
*/
protected $factory;

/**
* JsonMiddleware constructor.
*
*
@param ResponseFactory $factory
*/
public function __construct(ResponseFactory $factory)
{
$this->factory = $factory;
}

/**
* Handle an incoming request.
*
*
@param \Illuminate\Http\Request $request
*
@param \Closure $next
*
@return mixed
*/
public function handle($request, Closure $next)
{
// First, set the header so any other middleware knows we're
// dealing with a should-be JSON response.
$request->headers->set('Accept', 'application/json');

// Get the response
$response = $next($request);

// If the response is not strictly a JsonResponse, we make it
if (!$response instanceof JsonResponse) {
$response = $this->factory->json(
$response->content(),
$response->status(),
$response->headers->all()
);
}

return $response;

}
}

And you can even use a fourth parameter to set the type of JSON encoding for the resulting response. Neat!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Italo Baeza Cabrera
Italo Baeza Cabrera

Written by Italo Baeza Cabrera

Graphic Designer graduate. Full Stack Web Developer. Retired Tech & Gaming Editor. https://italobc.com

Responses (3)

Write a response