Different Response(JSON and webpage) in API and Website for Laravel 404 and 500?
Expects JSON
is about headers, i do not like that solution for API
errors, you can access the API
through a browser. My solution is most of the times to filter by the URL
route, because it starts with "api/..."
, which can be done like so $request->is('api/*')
.
If you have your routes that are not prefixes with /api
, then this will not work. Change the logic to fit with your own structure.
public function render($request, Exception $exception)
{
if ($exception instanceof NotFoundHttpException) {
if ($request->is('api/*')) {
return response()->json(['error' => 'Not Found'], 404);
}
return response()->view('404', [], 404);
}
return parent::render($request, $exception);
}
Just wanted to add an alternative to the above answers, which all seem to work as well.
After having the same problem and digging deeper, I took a slightly different approach:
your exception handle calls
parent::render(...)
. If you look into that function, it will render a json response if your request indicates that itwantsJson()
[see hints how that works here]now, to turn all responses (including exceptions) to json I used the Jsonify Middleware idea from here, but applied it to the api MiddlewareGroup, which is by default assigned to RouteServiceProvider::mapApiRoutes()
Here is one way to implement it (very similar to referenced answer from above):
Create the file
app/Http/Middleware/Jsonify.php
<?php namespace App\Http\Middleware; use Closure; class Jsonify { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ( $request->is('api/*') ) { $request->headers->set('Accept', 'application/json'); } return $next($request); } }
Add the middleware reference to your $routeMiddleware table of your
app/Http/Kernel.php
file:protected $routeMiddleware = [ ... 'jsonify' => \App\Http\Middleware\Jsonify::class, ... ];
In that same Kernel file, add the jsonify name to the api group:
protected $middlewareGroups = [ ... 'api' => [ 'jsonify', 'throttle:60,1', 'bindings', ], ... ];
Result is that the middleware gets loaded for any requests that fall into the 'api' group. If the request url begins with api/
(which is slightly redundant I think) then the header gets added by the Jsonify Middleware. This will tell the ExceptionHandler::render() that we want a json output.