Maelfjord's avatar

Laravel API returning webpages

First time here! I've been testing converting my first project into an API and everything is going well so far except for one thing: Laravel for some reason returns webpages when it should exclusively return JSON along with a status code no matter the circumstances.

I'm using Postman to test my routes and I discovered that they return a webpage when:

  1. I try to send a request that doesn't have the header 'Accept' specifically set to 'application/json'; and
  2. I purposefully send a bad request (i.e. the password confirmation is wrong, or some keys were not sent) to trigger the request validation logic.

When I looked at the data received by Postman, it has a status of 200 with the body being the HTML to the home page when it should've been 422 with a body of the JSON of the request validator.

Looking at the logs of the server, it appears that immediately after accessing the requested route ('/api/register'), it immediately requests the index page ('/').

I have some guesses on why this happens but I'm not sure. I've tried the workaround of forcing JSON response using a middleware but it doesn't seem to work. What is happening here and how do I fix it?

0 likes
7 replies
Snapey's avatar

All API request must specify Accept: header to tell laravel that a json reply is expected.

1 like
Maelfjord's avatar

@Snapey I'm aware, but I want to handle the cases where the 'Accept' header is '/' (any), which is the default for some.

Maelfjord's avatar

@Snapey Oh, ok then thanks for the help. That's kind of a bummer for me. I was hoping there is a workaround like forcing the sending of JSON if Laravel detects that it is an API call. Oh well, I'm going to try researching and experimenting for a bit and I'll update if I found a solution.

Maelfjord's avatar

@Snapey This works, thank you! Though instead of throwing an exception, I made it so that it returns a 400 error and a JSON message because exceptions still return a web page.

Maelfjord's avatar
Maelfjord
OP
Best Answer
Level 1

Update: For future reference, my complete solution is:

  1. I made a middleware named ForceJsonMiddleware:
class ForceJsonMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        if(!$request->wantsJson()) {
            abort(response()->json([
                'message' => 'This resource only supports JSON responses (set header "Accept" to "application/json").'
            ], 400));
        }

        return $next($request);
    }
}
  1. For convinience, middleware alias is set in bootstrap/app.php:
$middleware->alias([
      'force-json' => ForceJsonMiddleware::class,
]);
  1. To prevent conflicts with middleware priority (especially when using auth middleware), the middleware priority is set to:
$middleware->priority([
      ForceJsonMiddleware::class
]);

Please or to participate in this conversation.