Article in English can be found on dev.to/arxeiss/force-json-response-on-all-api-routes-in-laravel-29h
Popisovaný problém vzniká hlavně v situacích, kdy server vrací nějaký chybový kód. Převážně tedy 403 Unauthorized
, 404 Not Found
nebo při nevalidních datech 422 Unprocessable Entity
. Situace je možné si jednoduše nasimulovat vložením následujícího kódu do routes/api.php a prováděním požadavků například přes Postman nebo prohlížeč.
use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::get('health-check', function () { return response()->json([ 'status' => 'OK', 'timestamp' => Carbon::now() ]); }); Route::post('settings', function (Request $request) { $request->validate([ 'entry' => 'required|string|min:5' ]); return 'OK'; });
Na obrázku lze vidět, že ve všech situacích je response ze serveru ve formátu text/html
, nikoli application/json
. V některých situacích je uživatel dokonce přesměrován na úplně jinou stránku.
Jak vynutit JSON response
Laravel kontroluje hlavičku Accept
v požadavku a podle té se rozhoduje, v jakém formátu odešle odpověď. Pokud je tedy přítomna hlavička Accept: application/json
, odpověď bude odeslána ve formě JSON. Jenže browser či Postman často posílají hlavičku Accept: */*
. Příchozí požadavek je tedy nutné upravit a tuto hlavičku přepsat.
Vlastní middleware a route fallback
Middleware v tomto případě poslouží nejlépe. Stačí vytvořit nový soubor s obsahem níže v app/Http/Middleware/ForceJsonResponse.php. Stejného efektu lze docílit také pomocí příkazu php artisan make:middleware ForceJsonResponse
. Vytvořený middleware je pak nutné zaregistrovat pro všechny API routy v app/Http/Kernel.php. Posledním krokem je vytvoření fallback routy, tento krok není povinný, je ale vhodnější.
namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class ForceJsonResponse { public function handle(Request $request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } }
namespace App\Http; class Kernel extends \Illuminate\Foundation\Http\Kernel { ... protected $middlewareGroups = [ ... 'api' => [ \App\Http\Middleware\ForceJsonResponse::class, ... ], ]; }
// routes/api.php
Route::fallback(function (){ abort(404, 'API resource not found'); });
I nadále může být vráceno HTML
Kód výše vyřeší chybové hlášky. Přesto Laravel vrátí HTML, pokud je z controlleru vrácen čistý text. Tedy výsledek příkladu 3 na obrázku výše bude stále stejný. I tento problém je možné vyřešit middlewarem, detailnější popis je na blogu DarkGhostHunter. Osobně ale preferuji použít Response factory a vrátit opravdu JSON response. Tedy upravit kód jak je znázorněno níže.
Route::post('settings', function (Request $request) { $request->validate([ 'entry' => 'required|string|min:5' ]); // return 'OK';
return response()->json('OK'); });
Vlastní zkušenosti s API a JSON v Laravelu můžete sdílet v komentářích
Buď první, kdo přidá komentář. Zatím zde nic není