# 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.
