# API-Dokumentation Diese Dokumentation bietet einen Überblick über die API des Frameworks und wie Sie sie verwenden können, um RESTful APIs zu erstellen. ## Einführung Das Framework bietet umfassende Unterstützung für die Erstellung von RESTful APIs mit Funktionen wie: - Einfache Routendefinition für API-Endpunkte - Automatische Konvertierung von Daten in JSON - Validierung von Anfragen - Authentifizierung und Autorisierung - Versionierung - Rate Limiting - API-Dokumentation ## API-Routen definieren ### Grundlegende API-Routen Sie können API-Routen in der Datei `config/routes.php` definieren: ```php use App\Framework\Routing\Router; use App\Application\Controllers\Api\UserController; return function (Router $router) { $router->group('/api', function (Router $router) { $router->get('/users', [UserController::class, 'index']); $router->get('/users/{id}', [UserController::class, 'show']); $router->post('/users', [UserController::class, 'store']); $router->put('/users/{id}', [UserController::class, 'update']); $router->delete('/users/{id}', [UserController::class, 'destroy']); }); }; ``` ### API-Ressourcen-Routen Für RESTful APIs können Sie API-Ressourcen-Routen verwenden: ```php $router->apiResource('users', UserController::class); ``` Dies erstellt die folgenden Routen: | HTTP-Methode | URI | Aktion | Routenname | |--------------|------------------|----------|----------------| | GET | /users | index | users.index | | POST | /users | store | users.store | | GET | /users/{user} | show | users.show | | PUT/PATCH | /users/{user} | update | users.update | | DELETE | /users/{user} | destroy | users.destroy | ### Verschachtelte API-Ressourcen Sie können auch verschachtelte API-Ressourcen definieren: ```php $router->apiResource('users.posts', UserPostController::class); ``` Dies erstellt Routen wie: - `/users/{user}/posts` - `/users/{user}/posts/{post}` ### API-Versionierung Sie können verschiedene Versionen Ihrer API unterstützen: ```php $router->group('/api/v1', function (Router $router) { $router->apiResource('users', Api\V1\UserController::class); }); $router->group('/api/v2', function (Router $router) { $router->apiResource('users', Api\V2\UserController::class); }); ``` ## API-Controller API-Controller sind spezielle Controller, die JSON-Antworten zurückgeben: ```php namespace App\Application\Controllers\Api; use App\Framework\Http\Controller; use App\Framework\Http\Request; use App\Framework\Http\Response; use App\Application\Models\User; class UserController extends Controller { public function index(Request $request): Response { $users = User::all(); return $this->json([ 'data' => $users ]); } public function show(Request $request, int $id): Response { $user = User::find($id); if (!$user) { return $this->json([ 'error' => 'Benutzer nicht gefunden' ], 404); } return $this->json([ 'data' => $user ]); } public function store(Request $request): Response { $this->validate($request, [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:8', ]); $user = User::create($request->only(['name', 'email', 'password'])); return $this->json([ 'data' => $user, 'message' => 'Benutzer erstellt' ], 201); } public function update(Request $request, int $id): Response { $user = User::find($id); if (!$user) { return $this->json([ 'error' => 'Benutzer nicht gefunden' ], 404); } $this->validate($request, [ 'name' => 'string|max:255', 'email' => 'email|unique:users,email,' . $id, ]); $user->fill($request->only(['name', 'email'])); $user->save(); return $this->json([ 'data' => $user, 'message' => 'Benutzer aktualisiert' ]); } public function destroy(Request $request, int $id): Response { $user = User::find($id); if (!$user) { return $this->json([ 'error' => 'Benutzer nicht gefunden' ], 404); } $user->delete(); return $this->json([ 'message' => 'Benutzer gelöscht' ]); } } ``` ## API-Antworten ### Erfolgsantworten Für Erfolgsantworten können Sie die `json`-Methode verwenden: ```php // 200 OK return $this->json([ 'data' => $users ]); // 201 Created return $this->json([ 'data' => $user, 'message' => 'Benutzer erstellt' ], 201); // 204 No Content return $this->noContent(); ``` ### Fehlerantworten Für Fehlerantworten können Sie ebenfalls die `json`-Methode verwenden: ```php // 400 Bad Request return $this->json([ 'error' => 'Ungültige Anfrage' ], 400); // 401 Unauthorized return $this->json([ 'error' => 'Nicht autorisiert' ], 401); // 403 Forbidden return $this->json([ 'error' => 'Zugriff verweigert' ], 403); // 404 Not Found return $this->json([ 'error' => 'Benutzer nicht gefunden' ], 404); // 422 Unprocessable Entity (Validierungsfehler) return $this->json([ 'error' => 'Validierungsfehler', 'errors' => $validator->errors() ], 422); // 500 Internal Server Error return $this->json([ 'error' => 'Serverfehler' ], 500); ``` ### Konsistente Antwortstruktur Es ist wichtig, eine konsistente Antwortstruktur für Ihre API zu haben: ```php // Erfolgsantwort return $this->json([ 'success' => true, 'data' => $data, 'message' => $message, 'meta' => [ 'pagination' => [ 'total' => $total, 'per_page' => $perPage, 'current_page' => $currentPage, 'last_page' => $lastPage, ] ] ]); // Fehlerantwort return $this->json([ 'success' => false, 'error' => $errorMessage, 'errors' => $validationErrors, 'code' => $errorCode ], $statusCode); ``` ## API-Ressourcen API-Ressourcen ermöglichen es Ihnen, Modelle in JSON-Antworten zu transformieren: ```php namespace App\Application\Resources; use App\Framework\Http\Resources\JsonResource; use App\Application\Models\User; class UserResource extends JsonResource { public function toArray(): array { /** @var User $this->resource */ return [ 'id' => $this->resource->id, 'name' => $this->resource->name, 'email' => $this->resource->email, 'created_at' => $this->resource->created_at->format('Y-m-d H:i:s'), 'updated_at' => $this->resource->updated_at->format('Y-m-d H:i:s'), ]; } } ``` Verwenden Sie die Ressource in Ihrem Controller: ```php use App\Application\Resources\UserResource; public function show(Request $request, int $id): Response { $user = User::find($id); if (!$user) { return $this->json([ 'error' => 'Benutzer nicht gefunden' ], 404); } return $this->json([ 'data' => new UserResource($user) ]); } public function index(Request $request): Response { $users = User::all(); return $this->json([ 'data' => UserResource::collection($users) ]); } ``` ## API-Authentifizierung ### Token-basierte Authentifizierung Das Framework unterstützt Token-basierte Authentifizierung für APIs: ```php namespace App\Application\Controllers\Api; use App\Framework\Http\Controller; use App\Framework\Http\Request; use App\Framework\Http\Response; use App\Framework\Auth\Auth; use App\Framework\Auth\Token; class AuthController extends Controller { public function login(Request $request): Response { $this->validate($request, [ 'email' => 'required|email', 'password' => 'required|string', ]); $credentials = $request->only(['email', 'password']); if (!Auth::attempt($credentials)) { return $this->json([ 'error' => 'Ungültige Anmeldeinformationen' ], 401); } $user = Auth::user(); $token = Token::create($user); return $this->json([ 'data' => [ 'user' => $user, 'token' => $token, 'token_type' => 'Bearer', ] ]); } public function logout(Request $request): Response { $token = $request->bearerToken(); if ($token) { Token::revoke($token); } return $this->json([ 'message' => 'Erfolgreich abgemeldet' ]); } } ``` ### Authentifizierung mit dem Token ```php namespace App\Application\Middleware; use App\Framework\Http\Middleware; use App\Framework\Http\Request; use App\Framework\Http\Response; use App\Framework\Auth\Token; class ApiAuthMiddleware implements Middleware { public function handle(Request $request, callable $next): Response { $token = $request->bearerToken(); if (!$token || !Token::validate($token)) { return response()->json([ 'error' => 'Nicht autorisiert' ], 401); } $user = Token::getUser($token); Auth::setUser($user); return $next($request); } } ``` Registrieren Sie die Middleware: ```php // In der Middleware-Konfiguration $middleware->group('api', [ ApiAuthMiddleware::class ]); // In den Routen $router->group('/api', function (Router $router) { // Öffentliche Routen $router->post('/login', [AuthController::class, 'login']); // Geschützte Routen $router->group('', function (Router $router) { $router->apiResource('users', UserController::class); $router->post('/logout', [AuthController::class, 'logout']); })->middleware('api'); }); ``` ## API-Validierung Die Validierung für APIs funktioniert ähnlich wie für reguläre Anfragen, gibt jedoch JSON-Antworten zurück: ```php public function store(Request $request): Response { $validator = new Validator($request->all(), [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:8', ]); if ($validator->fails()) { return $this->json([ 'error' => 'Validierungsfehler', 'errors' => $validator->errors() ], 422); } $user = User::create($validator->validated()); return $this->json([ 'data' => $user, 'message' => 'Benutzer erstellt' ], 201); } ``` Oder mit der `validate`-Methode: ```php public function store(Request $request): Response { try { $this->validate($request, [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:8', ]); } catch (ValidationException $e) { return $this->json([ 'error' => 'Validierungsfehler', 'errors' => $e->errors() ], 422); } $user = User::create($request->only(['name', 'email', 'password'])); return $this->json([ 'data' => $user, 'message' => 'Benutzer erstellt' ], 201); } ``` ## API-Paginierung Das Framework unterstützt Paginierung für API-Antworten: ```php public function index(Request $request): Response { $page = $request->query('page', 1); $perPage = $request->query('per_page', 15); $users = User::paginate($perPage, $page); return $this->json([ 'data' => UserResource::collection($users->items()), 'meta' => [ 'pagination' => [ 'total' => $users->total(), 'per_page' => $users->perPage(), 'current_page' => $users->currentPage(), 'last_page' => $users->lastPage(), ] ] ]); } ``` ## API-Filterung und Sortierung Sie können Filterung und Sortierung für Ihre API implementieren: ```php public function index(Request $request): Response { $query = User::query(); // Filterung if ($request->has('name')) { $query->where('name', 'like', '%' . $request->query('name') . '%'); } if ($request->has('email')) { $query->where('email', 'like', '%' . $request->query('email') . '%'); } if ($request->has('role')) { $query->whereHas('roles', function ($q) use ($request) { $q->where('name', $request->query('role')); }); } // Sortierung $sortBy = $request->query('sort_by', 'created_at'); $sortDirection = $request->query('sort_direction', 'desc'); $allowedSortFields = ['id', 'name', 'email', 'created_at']; if (in_array($sortBy, $allowedSortFields)) { $query->orderBy($sortBy, $sortDirection === 'asc' ? 'asc' : 'desc'); } // Paginierung $page = $request->query('page', 1); $perPage = $request->query('per_page', 15); $users = $query->paginate($perPage, $page); return $this->json([ 'data' => UserResource::collection($users->items()), 'meta' => [ 'pagination' => [ 'total' => $users->total(), 'per_page' => $users->perPage(), 'current_page' => $users->currentPage(), 'last_page' => $users->lastPage(), ] ] ]); } ``` ## API-Rate Limiting Das Framework bietet Rate Limiting für APIs, um Missbrauch zu verhindern: ```php namespace App\Application\Middleware; use App\Framework\Http\Middleware; use App\Framework\Http\Request; use App\Framework\Http\Response; use App\Framework\Cache\Cache; class RateLimitMiddleware implements Middleware { private int $maxRequests; private int $timeWindow; public function __construct(int $maxRequests = 60, int $timeWindow = 60) { $this->maxRequests = $maxRequests; $this->timeWindow = $timeWindow; } public function handle(Request $request, callable $next): Response { $key = 'rate_limit:' . $this->getIdentifier($request); $requests = Cache::get($key, 0); if ($requests >= $this->maxRequests) { return response()->json([ 'error' => 'Zu viele Anfragen', 'message' => 'Bitte versuchen Sie es später erneut' ], 429); } Cache::put($key, $requests + 1, $this->timeWindow); $response = $next($request); $response->headers->set('X-RateLimit-Limit', $this->maxRequests); $response->headers->set('X-RateLimit-Remaining', $this->maxRequests - $requests - 1); return $response; } private function getIdentifier(Request $request): string { if (Auth::check()) { return 'user:' . Auth::id(); } return 'ip:' . $request->ip(); } } ``` Registrieren Sie die Middleware: ```php // In der Middleware-Konfiguration $middleware->group('api', [ RateLimitMiddleware::class ]); // Oder mit Parametern $middleware->group('api', [ new RateLimitMiddleware(100, 60) // 100 Anfragen pro Minute ]); ``` ## API-Dokumentation Das Framework unterstützt die automatische Generierung von API-Dokumentation mit OpenAPI/Swagger: ```php namespace App\Application\Controllers\Api; use App\Framework\Http\Controller; use App\Framework\Http\Request; use App\Framework\Http\Response; use App\Application\Models\User; /** * @OA\Tag( * name="Users", * description="API-Endpunkte für die Benutzerverwaltung" * ) */ class UserController extends Controller { /** * @OA\Get( * path="/api/users", * summary="Liste aller Benutzer abrufen", * tags={"Users"}, * @OA\Parameter( * name="page", * in="query", * description="Seitennummer", * @OA\Schema(type="integer") * ), * @OA\Parameter( * name="per_page", * in="query", * description="Anzahl der Elemente pro Seite", * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="Erfolgreiche Operation", * @OA\JsonContent( * @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/User")), * @OA\Property(property="meta", type="object") * ) * ) * ) */ public function index(Request $request): Response { // ... } /** * @OA\Get( * path="/api/users/{id}", * summary="Einen bestimmten Benutzer abrufen", * tags={"Users"}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="Benutzer-ID", * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="Erfolgreiche Operation", * @OA\JsonContent( * @OA\Property(property="data", ref="#/components/schemas/User") * ) * ), * @OA\Response( * response=404, * description="Benutzer nicht gefunden", * @OA\JsonContent( * @OA\Property(property="error", type="string") * ) * ) * ) */ public function show(Request $request, int $id): Response { // ... } // Weitere Methoden mit Dokumentation... } /** * @OA\Schema( * schema="User", * required={"id", "name", "email"}, * @OA\Property(property="id", type="integer", format="int64"), * @OA\Property(property="name", type="string"), * @OA\Property(property="email", type="string", format="email"), * @OA\Property(property="created_at", type="string", format="date-time"), * @OA\Property(property="updated_at", type="string", format="date-time") * ) */ ``` Generieren Sie die API-Dokumentation: ```bash php console.php api:docs ``` Dies erstellt eine OpenAPI/Swagger-Dokumentation, die Sie in einem Browser anzeigen können. ## Beste Praktiken für APIs ### Versionierung Versionieren Sie Ihre API, um Änderungen zu ermöglichen, ohne bestehende Clients zu beeinträchtigen: ```php $router->group('/api/v1', function (Router $router) { // API v1 Routen }); $router->group('/api/v2', function (Router $router) { // API v2 Routen }); ``` ### Konsistente Benennung Verwenden Sie konsistente Benennungskonventionen für Ihre API-Endpunkte: - Verwenden Sie Substantive im Plural für Ressourcen (z.B. `/users` statt `/user`) - Verwenden Sie Kebab-Case für URLs (z.B. `/user-profiles` statt `/userProfiles`) - Verwenden Sie Camel-Case für JSON-Eigenschaften (z.B. `firstName` statt `first_name`) ### HTTP-Statuscodes Verwenden Sie die richtigen HTTP-Statuscodes: - 200 OK: Erfolgreiche Anfrage - 201 Created: Ressource erfolgreich erstellt - 204 No Content: Erfolgreiche Anfrage ohne Inhalt - 400 Bad Request: Ungültige Anfrage - 401 Unauthorized: Authentifizierung erforderlich - 403 Forbidden: Keine Berechtigung - 404 Not Found: Ressource nicht gefunden - 422 Unprocessable Entity: Validierungsfehler - 429 Too Many Requests: Rate Limit überschritten - 500 Internal Server Error: Serverfehler ### Fehlerbehandlung Implementieren Sie eine konsistente Fehlerbehandlung: ```php try { // Code, der eine Exception werfen könnte } catch (ValidationException $e) { return $this->json([ 'error' => 'Validierungsfehler', 'errors' => $e->errors() ], 422); } catch (AuthorizationException $e) { return $this->json([ 'error' => 'Nicht autorisiert', 'message' => $e->getMessage() ], 403); } catch (NotFoundException $e) { return $this->json([ 'error' => 'Nicht gefunden', 'message' => $e->getMessage() ], 404); } catch (\Exception $e) { // Protokollieren Sie den Fehler $this->logger->error('API-Fehler', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return $this->json([ 'error' => 'Serverfehler', 'message' => 'Ein unerwarteter Fehler ist aufgetreten' ], 500); } ``` ### Dokumentation Dokumentieren Sie Ihre API gründlich: - Beschreiben Sie jeden Endpunkt - Dokumentieren Sie alle Parameter - Geben Sie Beispiele für Anfragen und Antworten - Erklären Sie Fehlerszenarien ## Weitere Informationen - [Routing-Anleitung](../guides/routing.md): Erfahren Sie mehr über das Routing-System. - [Controller-Anleitung](../guides/controllers.md): Erfahren Sie mehr über Controller. - [Validierungs-Anleitung](../guides/validation.md): Erfahren Sie mehr über die Validierung von Anfragen. - [Sicherheits-Anleitung](../guides/security.md): Erfahren Sie mehr über die Sicherheitsfunktionen des Frameworks. - [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.