Laravel: Convert all responses to JSON automatically

Laravel: Convert all responses to JSON automaticallyBecause not every person in the world wants HTML, nor use response()->json() in every freaking controller.

Italo BaezaBlockedUnblockFollowFollowingJan 9And it will beIf 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 MiddlewareWell, there is very simple way to “force” your app to return JSON, and that is with one line middleware.

We will call it JsonMiddleware because indicates the response should be JSON, but doesn’t forces it.

<?phpnamespace AppHttpMiddleware;use Closure;class JsonMiddleware{ /** * Handle an incoming request.

* * @param IlluminateHttpRequest $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 Accept header is application/json or any other JSON-like header.

So, the application will try to push a JSON response automatically, when possible.

The placeIn our AppHtmlKernel.

php, 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 AppHttpMiddlewareApiJsonMiddleware::class, ],];If we need more control of where we can put it, we can register an alias like return-json in the $routeMiddleware.

/** * 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' => AppHttpMiddlewareApiJsonMiddleware::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 OrderLaravel conveniently has a global order for middlewares.

When they are called in a route, it will run them in the same order displayed on $middlewarePriority.

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 AppHttpMiddlewareApiJsonMiddleware::class, // Then the rest.

];And that’s it.

Bonus: Forcing a JSON ResponseAdditionally to our JsonMiddleware, we can ensure the response is a IlluminateHttpJsonResponse instance.

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

<?phpnamespace AppHttpMiddleware;use Closure;use IlluminateContractsRoutingResponseFactory;use IlluminateHttpJsonResponse;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 IlluminateHttpRequest $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.


. More details

Leave a Reply