Zum Inhalt springen

REST API Design: Best Practices für Symfony-Projekte

Veröffentlicht am 28. Dez. 2025 | ca. 1 Min. Lesezeit |

APIs sind das Rückgrat moderner Webanwendungen. Ein durchdachtes API-Design erleichtert die Zusammenarbeit zwischen Frontend und Backend und macht die Schnittstelle langfristig wartbar.

Konsistente URL-Struktur

RESTful URLs sollten Ressourcen beschreiben, nicht Aktionen:

GET    /api/v1/products          # Liste aller Produkte
GET    /api/v1/products/42       # Einzelnes Produkt
POST   /api/v1/products          # Neues Produkt erstellen
PUT    /api/v1/products/42       # Produkt aktualisieren
DELETE /api/v1/products/42       # Produkt löschen

In Symfony nutze ich dafür Attribute-basiertes Routing:

<?php

declare(strict_types=1);

namespace App\Controller\Api;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/api/v1/products')]
class ProductApiController extends AbstractController
{
    #[Route('', methods: ['GET'])]
    public function list(): JsonResponse
    {
        // Pagination, Filter, Sorting
        return $this->json([
            'data' => $products,
            'meta' => [
                'total' => $total,
                'page' => $page,
                'per_page' => $perPage,
            ],
        ]);
    }

    #[Route('/{id}', methods: ['GET'])]
    public function show(int $id): JsonResponse
    {
        // Single resource
        return $this->json(['data' => $product]);
    }
}

Einheitliche Fehlerbehandlung

Ein konsistentes Fehlerformat ist entscheidend. Ich verwende einen zentralen Exception-Listener:

<?php

declare(strict_types=1);

namespace App\EventListener;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

class ApiExceptionListener
{
    public function onKernelException(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();
        $statusCode = $exception instanceof HttpExceptionInterface
            ? $exception->getStatusCode()
            : 500;

        $response = new JsonResponse([
            'error' => [
                'code' => $statusCode,
                'message' => $exception->getMessage(),
            ],
        ], $statusCode);

        $event->setResponse($response);
    }
}

Validierung und DTOs

Eingehende Daten sollten immer über DTOs validiert werden:

<?php

declare(strict_types=1);

namespace App\Dto;

use Symfony\Component\Validator\Constraints as Assert;

class CreateProductRequest
{
    #[Assert\NotBlank]
    #[Assert\Length(min: 3, max: 255)]
    public string $name;

    #[Assert\NotBlank]
    #[Assert\Positive]
    public float $price;

    #[Assert\NotBlank]
    public string $description;
}

Versionierung

API-Versionierung über die URL (/api/v1/) ist einfach und explizit. Für größere Projekte kann auch Header-basierte Versionierung sinnvoll sein. Wichtig ist, dass eine einmal veröffentlichte API-Version stabil bleibt und Breaking Changes nur in neuen Versionen eingeführt werden.

Ein gut designtes API spart langfristig viel Entwicklungszeit – sowohl beim eigenen Team als auch bei externen Konsumenten der Schnittstelle.

Thomas Wunner

Thomas Wunner

Fachinformatiker für Anwendungsentwicklung mit Ausbildereignungsprüfung und über 14 Jahre Erfahrung im Aufbau skalierbarer Webanwendungen mit Symfony und Shopware. Abseits der Tastatur ist Thomas als Rettungsschwimmer in der Wasserwacht aktiv, legt als DJ auf und erkundet die Umgebung auf dem Motorrad.

Kommentare

Kommentare werden von Remark42 bereitgestellt. Beim Laden werden Daten an unseren Kommentar-Server übertragen.