Laravel: API-Antworten und -Fehlermeldungen abfangen und manipulieren.

Zu einem guten API-Design gehört auch, sich Gedanken über das Format der Antworten zu machen. Idealerweise folgt sie einem bestimmten Standard, der gut dokumentiert und leicht verständlich ist, sodass die Konsumenten des API keine unnötigen Schwierigkeiten erleben.

Laravel dokumentiert die Verwendung seiner Response-Klasse recht ausführlich und illustriert einige Anwendungen und Beispiele. Benutzt man die angebotenen Helfer-Methoden in einem API-Kontext, wird einem die Konvertierung zu JSON und das Setzen der Headers abgenommen.

Doch hin und wieder will man in das Format dieser Antworten eingreifen. In Online-Beiträgen sieht man zum Beispiel häufig, wie Programmierer den Daten-Anteil ihrer API-Antwort in einem Daten-Objekt innerhalb der Antwort kapseln, oder ihren Fehler-Antworten einen internen Fehlercode anhängen, der unabhängig von den HTTP-Status-Codes definiert wurde.

Typischerweise lösen besagte Programmierer die oben genannten Aufgaben, indem sie an zwei Stellen ansetzen:

  • Die Fehler werden in der Klasse App\Exceptions\Handler behandelt.
  • Antworten werden in den jeweiligen Controllern über die Helfermethode response() formatiert.

Es gibt aber einen alternativen Weg, beide diese Szenarien, also reguläre Response / JsonResponse einerseits und Exceptions andererseits gemeinsam zu verändern, ohne dabei die beiden genannten Punkte anfassen zu müssen. Der Ansatz ist gut vergleichbar mit dem Vorgehen in ExpressJS, wo es gängige Praxis ist, sich überall in der Behandlung und Antwort zu einer Anfrage mithilfe einer Middelware in den Prozess einzuhaken und die Daten zu manipulieren.

Auch Laravel kennt Middleware, welche typischerweise auf die eingehenden Requests angewandt werden, um beispielsweise den angefragten Content-Type oder die CORS-Headers zu überprüfen. Wir benutzen diese Middleware, um die Antwort abzufangen und vor dem zurücksenden zu verändern.

Um die Middleware zu erstellen und zu registrieren gehen wir natürlich genauso vor wie immer:

php artisan make:middleware AddStuffToResponseMiddleware

Wir erstellen uns eine neue Middelware mit Artisan. Danach registrieren wir die Middleware. In unserem Fall wollen wir nur die API-Requests anfassen, darum fügen wir unsere erstellte Middelwareklasse der ‚api‘-Gruppe in der Datei App\Http\Kernel hinzu. Und schon ist die Sache erledigt.

// In App\Http\Kernel
protected $middlewareGroups = [
    'web' => [ ... ],
    'api' => [
      
   \App\Http\Middleware\AddStuffToResponseMiddleware::class,
        'throttle:60,1',
        'auth:api',
    ],
];

Besonders interessant ist jetzt der kleine Abschnitt in der Dokumentation, der von „Before & After Middleware“ spricht. Das Beispiel für die After Middelware sieht genau so aus, wie wir das brauchen. Sie nimmt die Anfrage auf, lässt sie von der Applikation über die next()-Closure behandeln und fängt die Antwort in der $response-Variable.

<?php
namespace App\Http\Middleware;
use Closure;
class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        // Perform action
        return $response;
    }
}

Der Inhalt ist in der Regel vom Typ Illuminate\Http\Response (z.B. return response($stuff), 200) oder Illuminate\Http\JsonResponse (z.B. return response()->json($stuff, 200)). Die beiden Klassen haben aber einige Methoden gemeinsam.

$response->getStatusCode() // HTTP status code
$response->getOriginalContent() // Inhalt als PHP Objekt

Um jetzt zum Beispiel die Daten einem ‚data‘-Schlüssen zuzuordnen und in jedem Fall mit JSON zu antworten, können wir die folgenden Zeilen unserer eigenen Middleware hinzufügen:

<?php
namespace App\Http\Middleware;
use Closure;
class AddStuffToResponseMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        return response()->json(
            ['data => $response->getOriginalContent()], 
            $response->getStatusCode()
        );
    }
}

Wir können jetzt aus einem Controller wie gewohnt antworten, und es kommt immer ein JSON beim Konsumenten an, welches den Inhalt unserer Variable unter dem Key ‚data‘ erreichbar hat.

<?php
namespace App\Http\Controllers;
class SomeController extends Controller {
    public function index()
    {
        return response($someData, 200);
    }
}

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s