Laravel Lumen Ensure JSON response
Solution 1
You'll need to adjust your exception handler (app/Exceptions/Handler.php
) to return the response you want.
This is a very basic example of what can be done.
public function render($request, Exception $e)
{
$rendered = parent::render($request, $e);
return response()->json([
'error' => [
'code' => $rendered->getStatusCode(),
'message' => $e->getMessage(),
]
], $rendered->getStatusCode());
}
Solution 2
A more accurate solution based on @Wader's answer can be:
use Illuminate\Http\JsonResponse;
public function render($request, Exception $e)
{
$parentRender = parent::render($request, $e);
// if parent returns a JsonResponse
// for example in case of a ValidationException
if ($parentRender instanceof JsonResponse)
{
return $parentRender;
}
return new JsonResponse([
'message' => $e instanceof HttpException
? $e->getMessage()
: 'Server Error',
], $parentRender->status());
}
Solution 3
Instead of touching the exception handler, I suggest you to add a middleware that sets the Accept
header to application/json
.
For example, you can create a middleware called RequestsAcceptJson
and define it this way:
<?php
namespace App\Http\Middleware;
use Closure;
class RequestsAcceptJson
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$acceptHeader = strtolower($request->headers->get('accept'));
// If the accept header is not set to application/json
// We attach it and continue the request
if ($acceptHeader !== 'application/json') {
$request->headers->set('Accept', 'application/json');
}
return $next($request);
}
}
Then you only need to register it as a global middleware to be run in every request to your api. In lumen you can do that by adding the class in the middleware call inside your bootstrap/app.php
$app->middleware([
App\Http\Middleware\RequestsAcceptJson::class
]);
With Laravel it's pretty much the same process. Now the error handler will always return a json instead of plain text/html.
Related videos on Youtube
John Fonseka
Updated on July 05, 2021Comments
-
John Fonseka almost 3 years
I am new to Laravel and to Lumen. I want to ensure I am always getting only a JSON object as output. How can I do this in Lumen?
I can get a JSON response using
response()->json($response);
. But when an error happens, API giving metext/html
errors. But I want onlyapplication/json
responses.Thanks in advance.
-
John Fonseka almost 8 yearsThanks for the answer. I have a little question however, Can I do this?
return response()->json(['code' => $rendered->getStatusCode(), 'message' => $e->getMessage()], $rendered->getStatusCode());
I searched for list of exceptions and couldn't find a list yet. -
Wader almost 8 yearsThat looks fine to me. Heres the signature for the
response()->json()
function. github.com/laravel/lumen-framework/blob/5.2/src/Http/… -
Derek Pollard about 6 yearsGood complete answer including the necessary class as well. upvote from me
-
Jason almost 5 yearsNote that this example will always return a
200
HTTP code. You probably don't want that. If usingfindOrFail()
for example, thecode
element will correctly show a404
, but the overall result will still be a200
, which it patently isn't. To fix this, pass$rendered->getStatusCode()
intojson()
as its second parameter. -
Kamlesh over 2 yearsany same suggestion for Lumen 8? Thanks