When I'm building an API, I usually only design it to accept JSON requests. I think this approach is pretty typical with modern Laravel applications. But by default, Laravel doesn't do anything to enforce this.
API routes will be served to a regular browser user or to an API client that doesn't correctly specify the Accept
header.
This can even get triggered if someone pastes an API endpoint URL into Slack or some other chat client that tries to load
link previews automatically.
This can lead to some annoying errors, especially if your API is expecting Sanctum authentication. For example, if you're
building an app that's purely an API with no user interface allowing normal login, you probably don't even have a login
route defined in your application. But the Authenticate
middleware and other parts of Laravel might try to bounce an
unauthenticated user to the login
route if they aren't requesting JSON. Now you'll get an HTTP 500 error since it can't
resolve the login
route.
All of this could be avoided if we just force any request to an API route to accept JSON. I like to do this with a simple middleware:
class RequiresJson
{
public function handle(Request $request, Closure $next): Response
{
if (!$request->wantsJson()) {
throw new NotAcceptableHttpException(
'Please request with HTTP header: Accept: application/json'
);
}
return $next($request);
}
}
You can either add this middleware to your api
middleware group, or to a route group in your routes/api.php
file.
The key is to make sure it runs before your Authenticate
middleware though.
With this in place, you don't get annoying errors and someone trying to hit your API without the header will get a friendly message explaining what they're doing wrong.
Hope this helps,
Joel
P.S. Have you seen Ash Allen's excellent book on Laravel APIs?