Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here
Tutorial Free

Laravel API 404 Response: Return JSON Instead of Webpage Error

May 07, 2019
2 min read

Tutorial last revisioned on June 12, 2025 with Laravel 12

If you're building a Laravel project with both Web and API sides, you need to customize error messages for each of them separately. In web-view there should be error pages, and API exceptions should return JSON with status codes. How to handle it? I will show you an example with case of Model Not Found 404.

Imagine this scenario - a web page user profile, and API-based similar request.

So, we have app/Http/Controllers/UserController.php:

public function show(User $user)
{
return view('users.show', compact('user'));
}

And then we have API - in app/Http/Controllers/API/V1/UserController.php:

public function show(User $user)
{
return $user;
}

The second example will just return JSON'ed Collection, without any web template. And that's fine.

The problem starts when you try to load that API call and the user is not found. Since we're using Route Model Binding here and passing (User $user) directly, under the hood it's launching User::findOrFail($id) method and throws exception of NotFoundHttpException and shows 404 page.

In API side, you also get an error page instead of JSON error:

So, our goal is to stay as it is for the web version, but override the API error handling to return a proper JSON.

To do that, we need to add this logic to the bootstrap/app.php class:

use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
api: __DIR__ . '/../routes/api.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
})
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->renderable(function (NotFoundHttpException $e, Request $request) {
if ($request->wantsJson()) {
return response()->json(['message' => 'Not Found!'], 404);
}
});
})->create();

And that's it, you will receive a well-formed response:

Do not forget to also set headers to accept JSON.

And it won't change the default behavior for web-based requests, it will still show good old 404 page.

For more tips how to handle API errors and exceptions, see my other in-depth article.

Enjoyed This Tutorial?

Get access to all premium tutorials, video and text courses, and exclusive Laravel resources. Join our community of 10,000+ developers.

Comments & Discussion

A�
Ali Özen ✓ Link copied!

In laravel 10+ using Throwable and $exception => $e may be good

public function render($request, \Exception|Throwable $e) { if ($e instanceof ModelNotFoundException && $request->wantsJson()) { return response()->json(['message' => 'Not Found!'], 404); }

return parent::render($request, $e);
}

But anyway I am not sure is this still working or my project is messed up?

A�
Ali Özen ✓ Link copied!

well I got the solution

In the doc

public function register(): void
{
$this->renderable(function (NotFoundHttpException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'Record not found.'
], 404);
}
});
}

just update the register. Don't forget to add

use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
A�
Ali Özen ✓ Link copied!

sorry for the bad styling on question. Forgot to add apostrophe

PK
Povilas Korop ✓ Link copied!

Hi, yes, the solution from the docs seems like the right one. Thanks for the comment!

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.