Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
838
docs/api/index.md
Normal file
838
docs/api/index.md
Normal file
@@ -0,0 +1,838 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user