Laravel Lumen Ensure JSON response

23,247

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.

Share:
23,247

Related videos on Youtube

John Fonseka
Author by

John Fonseka

Updated on July 05, 2021

Comments

  • John Fonseka
    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 me text/html errors. But I want only application/json responses.

    Thanks in advance.

  • John Fonseka
    John Fonseka almost 8 years
    Thanks 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
    Wader almost 8 years
    That looks fine to me. Heres the signature for the response()->json() function. github.com/laravel/lumen-framework/blob/5.2/src/Http/…
  • Derek Pollard
    Derek Pollard about 6 years
    Good complete answer including the necessary class as well. upvote from me
  • Jason
    Jason almost 5 years
    Note that this example will always return a 200 HTTP code. You probably don't want that. If using findOrFail() for example, the code element will correctly show a 404, but the overall result will still be a 200, which it patently isn't. To fix this, pass $rendered->getStatusCode() into json() as its second parameter.
  • Kamlesh
    Kamlesh over 2 years
    any same suggestion for Lumen 8? Thanks