Today I was working on an API written in Laravel for a React Native app with another developer.

He was trying to make requests to the Laravel backend and told me he kept receiving a response with a http status code of 302. 3XX http status codes are redirection status codes.

It turned out that he had not set an accept header on the requests to the server that the app was making.

By default if you dont set a requests accept headers they default to Accept: */*. With those set laravel responds with a Content-Type of text/html.

For the purpose of this project every api response needs to return JSON.

We can achieve this really easily by using middleware to overwrite the Accept headers on the incoming request and setting them to application/json.

Create a new middleware class:

1
php artisan make:middleware RespondWithJsonMiddleware

Now open the new file created in app/Http/Middleware and change the handle method to look like this:

1
2
3
4
5
6
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');

return $next($request);
}

And thats as simple as it gets, now we just need to apply that middleware to a given set of routes.

Applying to all API routes

For my purposes I wanted every request to return JSON so I added this new class to api global middleware group in app/Http/Kernel.php

1
2
3
4
5
6
7
...
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
App\Http\Middleware\RespondWithJsonMiddleware::class,
],
...

If we look at the app/Providers/RouteServiceProvider.php file we can see that this api middleware group is applied to all of the routes in ``routes/api.php`:

1
2
3
4
5
6
7
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}

Applying to specific routes

If we didn’t want to apply the new middleware to every api route and to a given controller we can do so like this.

First remove the new middleware from the api group

1
2
3
4
5
6
7
// app/Http/Kernel.php
...
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
...

Now add the new middleware item to the $routeMiddleware array in the same file

1
2
3
4
5
6
7
8
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
...
'respond.json' => App\Http\Middleware\RespondWithJsonMiddleware::class,
];

Then use the middleware as you normally would in your routes file

1
2
3
4
// routes/api.php
Route::group(['middleware' => ['respond.json']], function () {
// routes in here...
}

Anonymously in a controller

We can also apply this code to a controller using the controller middleware function.

1
2
3
4
5
6
7
8
9
10
11
12
13
class IndexController extends Controller
{

public function __construct()
{
$this->middleware(function ($request, $next) {
$request->headers->set('Accept', 'application/json');

return $next($request);
});
}

...