From f2bd89a8569375c80b5e18abe9540c310b5e1dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bar=C3=A1=C5=A1ek?= Date: Sun, 4 Jan 2026 11:22:54 +0100 Subject: [PATCH 1/3] Updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4f38912..a8a902c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea vendor composer.lock +.env From 190af59ddcae4f20f057fbeca558c75e00db70d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bar=C3=A1=C5=A1ek?= Date: Sun, 4 Jan 2026 11:25:20 +0100 Subject: [PATCH 2/3] Updated README.md --- README.md | 860 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 671 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index de48ec7..cf70930 100644 --- a/README.md +++ b/README.md @@ -8,307 +8,789 @@
-Structured REST API in PHP -========================== +# Structured REST API in PHP ![Integrity check](https://github.com/baraja-core/structured-api/workflows/Integrity%20check/badge.svg) -Full compatible smart structured API defined by schema. +A powerful, type-safe REST API framework for PHP 8.1+ with full Nette Framework integration. Define structured API endpoints as PHP classes with automatic parameter validation, response serialization, and built-in permission management. -- Define full type-hint input parameters, -- Validate returned data by schema, -- Full compatible with Nette framework, -- Inject dependencies by `#[Inject]` attribute (or old `@inject` annotation syntax) in public property. +## :dart: Key Features + +- **Type-safe endpoints** - Define full type-hint input parameters with automatic validation +- **Schema-based responses** - Return typed DTOs that are automatically serialized to JSON +- **Automatic endpoint discovery** - Endpoints are auto-registered via Nette DI container +- **Built-in permission system** - Role-based access control with `#[PublicEndpoint]` and `#[Role]` attributes +- **HTTP method routing** - Method names determine HTTP verb (GET, POST, PUT, DELETE) +- **Tracy debugger integration** - Visual debug panel for API request/response inspection +- **CORS handling** - Automatic Cross-Origin Resource Sharing support +- **Dependency injection** - Full DI support via constructor or `#[Inject]` attribute +- **Flash messages** - Built-in flash message system for API responses + +## :building_construction: Architecture Overview + +The package follows a layered architecture with clear separation of concerns: + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ HTTP Request │ +└─────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ ApiManager │ +│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ +│ │ URL Router │ │ CORS Handler │ │ Tracy Panel │ │ +│ │ /api/v1/{path} │ │ (Preflight) │ │ (Debug) │ │ +│ └────────┬────────┘ └──────────────────┘ └───────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Middleware Pipeline │ │ +│ │ ┌─────────────────────┐ ┌──────────────────────────────┐ │ │ +│ │ │ PermissionExtension │ │ Custom MatchExtensions │ │ │ +│ │ │ (Auth & Roles) │ │ (beforeProcess/afterProcess)│ │ │ +│ │ └─────────────────────┘ └──────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ Endpoint │ +│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ +│ │ BaseEndpoint │ │ Method Invoker │ │ Convention │ │ +│ │ (Your Logic) │ │ (Param Binding) │ │ (Formatting) │ │ +│ └────────┬────────┘ └──────────────────┘ └───────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ Response System │ │ +│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │ │ +│ │ │DTO Objects │ │StatusResp │ │ JsonResponse │ │ │ +│ │ │(Your Types)│ │(Ok/Error) │ │ (Serialized) │ │ │ +│ │ └────────────┘ └────────────┘ └────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ HTTP Response │ +│ (JSON with proper HTTP code) │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Core Components + +| Component | Description | +|-----------|-------------| +| **ApiManager** | Central orchestrator that handles routing, CORS, middleware execution, and response processing | +| **ApiExtension** | Nette DI extension for automatic service registration and configuration | +| **BaseEndpoint** | Abstract base class providing helper methods for sending responses | +| **Endpoint** | Interface that marks a class as an API endpoint | +| **MetaDataManager** | Discovers and registers endpoint classes using RobotLoader | +| **Convention** | Configuration entity for response formatting, date formats, and security settings | +| **PermissionExtension** | Middleware for authentication and role-based access control | +| **MatchExtension** | Interface for creating custom middleware (before/after processing hooks) | +| **Tracy Panel** | Debug panel showing request details, parameters, and response data | + +## :framed_picture: Tracy Debug Panel + +The package includes a comprehensive Tracy debug panel for inspecting API requests during development: ![Baraja Structured API debug Tracy panel](doc/tracy-panel-design.png) -📦 Installation & Basic Usage ------------------------------ +The panel displays: +- HTTP method and request URL +- Raw HTTP input parameters +- Resolved endpoint arguments after type casting +- Response type, HTTP code, and content type +- Complete serialized response data +- Request processing time in milliseconds -This package can be installed using [PackageRegistrator](https://github.com/baraja-core/package-manager) which is also part of the Baraja [Sandbox](https://github.com/baraja-core/sandbox). If you are not using it, you have to install the package manually following this guide. +## :package: Installation -A model configuration can be found in the `common.neon` file inside the root of the package. +It's best to use [Composer](https://getcomposer.org) for installation, and you can also find the package on +[Packagist](https://packagist.org/packages/baraja-core/structured-api) and +[GitHub](https://github.com/baraja-core/structured-api). -To manually install the package call Composer and execute the following command: +To install, simply use the command: ```shell $ composer require baraja-core/structured-api ``` -🛠️ API endpoint ---------------- +### Requirements + +- PHP 8.1 or higher +- Extensions: `json`, `mbstring`, `iconv` +- Nette Framework 3.x + +### Nette Framework Integration + +The package integrates automatically with Nette Framework. A model configuration can be found in the `common.neon` file inside the root of the package. + +If you use [PackageRegistrator](https://github.com/baraja-core/package-manager), the extension is registered automatically. Otherwise, register the extension manually in your `config.neon`: + +```neon +extensions: + structuredApi: Baraja\StructuredApi\ApiExtension +``` + +### Configuration Options + +```neon +structuredApi: + skipError: false # If true, silently logs API exceptions instead of throwing +``` + +## :rocket: Basic Usage -API endpoint is simple class with action methods and dependencies. For best comfort please use your custom BaseEndpoint with declaring all required dependencies. +### Creating Your First Endpoint -Simple example: +Create a class that extends `BaseEndpoint` with the suffix `Endpoint`: ```php sendJson([ - 'name' => 'Test API endpoint', - 'hello' => $hello, - ]); - } - - // or return simple array directly: - - /** - * @param array $data - */ - public function postCreateUser(array $data): array - { - return [ - 'state' => 'ok', - 'data' => $data, - ]; - } + public function __construct( + private ArticleRepository $articleRepository, + ) { + } + + public function actionDefault(): array + { + return [ + 'articles' => $this->articleRepository->findAll(), + ]; + } + + public function actionDetail(int $id): ArticleResponse + { + $article = $this->articleRepository->find($id); + + return new ArticleResponse( + id: $article->getId(), + title: $article->getTitle(), + content: $article->getContent(), + ); + } } ``` -Method `actionDefault` is used for request in format `/api/v1/test` with query parameter `?hello=...`. +This endpoint will be available at: +- `GET /api/v1/article` - calls `actionDefault()` +- `GET /api/v1/article/detail?id=123` - calls `actionDetail(123)` -Method `postCreateUser` will be called by POST request with all data. +### Response DTO Objects -Always return the response from the endpoint directly as the return type of the method. This makes static analysis easier for other tools (for example, for checking code integrity or generating documentation). The `sendJson()`, `sendOk()`, and `sendError()` methods are still supported, but may be marked as deprecated in the future. +For type-safe responses, create DTO classes: -📝 Endpoint registration ------------------------- +```php + + */ + public function actionDefault( + ?string $locale = null, + int $page = 1, + int $limit = 32, + ?string $status = null, + ?string $query = null, + ?\DateTimeInterface $filterFrom = null, + ?\DateTimeInterface $filterTo = null, + ?string $sort = null, + ?string $orderBy = null, + ): ArticleListResponse { + // All parameters are validated and properly typed + } +} +``` + +**Validation rules:** +- Parameters with default values are **optional** +- Parameters without defaults are **required** - request fails if missing +- Type mismatches trigger automatic conversion or error response +- The special parameter `array $data` receives all raw input data -For example: +### Accessing Raw Data + +For complex data structures, use the reserved `$data` parameter: ```php -final class OrderEndpoint extends BaseEndpoint +public function postProcessOrder(array $data): OrderResponse { - public function postProcessOrder(array $data): void - { - // variable $data contains all raw data from user. - } + // $data contains all raw POST data from the request } ``` -✅ Validation -------------- +## :left_speech_bubble: Response Methods -In the runtime, when calling methods, the passed arguments against the method definition and data types are validated. This ensures that the endpoint is never called with incorrect data. +`BaseEndpoint` provides several helper methods for sending responses: -The library guarantees that you will always get the data in the type you request. If you need to define the type more complicated, you can use a comment annotation. +### sendJson() -Combined example: +Send raw array data as JSON: ```php -final class ArticleEndpoint extends BaseEndpoint +public function actionDetail(int $id): void +{ + $this->sendJson([ + 'id' => $id, + 'title' => 'My Article', + 'content' => '...', + ]); +} +``` + +### sendOk() + +Send success response with optional data and message: + +```php +public function postCreate(string $title): void +{ + $article = $this->repository->create($title); + + $this->sendOk( + data: ['id' => $article->getId()], + message: 'Article created successfully', + ); +} +``` + +Response format: +```json { - /** - * @param string|null $locale in format "cs" or "en" - * @param int $page real page number for filtering, 1 => first page ... "n" page - * @param int $limit in interval <0, 500) - * @param string|null $status matching constant self::STATUS_* (null, all, published, trash) - * @param string|null $query smart search query - * @param string|null $filterFrom find all articles from this date - * @param string|null $filterTo find all articles to this date - * @param string|null $sort sort by supported field - * @param string|null $orderBy direction by `ASC` or `DESC` - */ - public function actionDefault( - ?string $locale = null, - int $page = 1, - int $limit = 32, - ?string $status = null, - ?string $query = null, - ?string $filterFrom = null, - ?string $filterTo = null, - ?string $sort = null, - ?string $orderBy = null, - ): void { - } + "state": "ok", + "message": "Article created successfully", + "code": 200, + "data": { + "id": 123 + } } ``` -The library takes full advantage of PHP 7 and always checks data types. If the data is passed in the wrong type (for example, a boolean cannot be passed by the GET method), it performs an automatic conversion or throws an error. +### sendError() + +Send error response: + +```php +public function actionDetail(int $id): void +{ + $article = $this->repository->find($id); + + if ($article === null) { + $this->sendError( + message: 'Article not found', + code: 404, + hint: 'Check if the article ID is correct', + ); + } -If the argument contains a default value, it is **automatically marked as optional**. If the user does not pass a value, the default is used. All mandatory arguments **must always be passed**, if not, your logic will not be called at all. + // ... +} +``` -🙋 Smart response ------------------ +Response format: +```json +{ + "state": "error", + "message": "Article not found", + "code": 404, + "hint": "Check if the article ID is correct" +} +``` -The library contains a number of built-in methods for elegant handling of all important return states. +### sendItems() -For example, if we want to get the detail of an article by ID and return its detail from the database, the use is completely intuitive: +Send paginated list of items: ```php -final class ArticleEndpoint extends BaseEndpoint +public function actionDefault(int $page = 1): void { - public function actionDetail(string $id): void - { - // your logic for fetch data from database - - // your response - $this->sendJson([ - 'id' => $id, - 'title' => 'My awesome article', - 'content' => '...', - ]); - } + $items = $this->repository->findPage($page); + $paginator = $this->repository->getPaginator(); + + $this->sendItems($items, $paginator, [ + 'totalCount' => $paginator->getTotalCount(), + ]); } ``` -Each method can return output either via `send` methods or directly as a type object. A more modern approach is to return the entire object, as this gives us type checking and the underlying basis for automatically generated documentation. +### Return Statement (Recommended) -> **Warning:** If you do not pass any output (by method or return statement), endpoint processing will fail. +The preferred approach is returning typed objects directly: -When processing actions, it is a good idea to return success or error information: +```php +public function actionDetail(int $id): ArticleResponse +{ + $article = $this->repository->find($id); + + return new ArticleResponse( + id: $article->getId(), + title: $article->getTitle(), + content: $article->getContent(), + ); +} +``` + +This enables: +- Static analysis and IDE support +- Automatic documentation generation +- Type safety at compile time + +## :bell: Flash Messages + +Add flash messages to any response: ```php -final class ArticleEndpoint extends BaseEndpoint +public function postUpdate(int $id, string $title): ArticleResponse { - public function createDetail(string $title, string $content, ?string $perex = null): void - { - try { - // creating in database... - $this->sendOk([ - 'id' => 123, - ]); - } catch (\Exception $e) { - $this->sendError('Can not create article because ...'); - } - } + $article = $this->repository->update($id, $title); + + $this->flashMessage('Article updated successfully', self::FlashMessageSuccess); + $this->flashMessage('Remember to publish your changes', self::FlashMessageInfo); + + return new ArticleResponse($article); } ``` -🔒 Permissions --------------- +Available flash message types: +- `FlashMessageSuccess` - success +- `FlashMessageInfo` - info +- `FlashMessageWarning` - warning +- `FlashMessageError` - error + +Flash messages are included in the response under `flashMessages` key: -> 🚩**Warning:** If you do not set the rights at all, by default all endpoints are private and you must log in to call them! 👮 +```json +{ + "id": 123, + "title": "Updated Article", + "flashMessages": [ + {"message": "Article updated successfully", "type": "success"}, + {"message": "Remember to publish your changes", "type": "info"} + ] +} +``` -All API requests are validated at runtime. If you want to allow all users access to your endpoints, please add the `#[PublicEndpoint]` attribute to class. +## :lock: Permissions & Security -For example (this endpoint will be public): +### Default Security Behavior + +**All endpoints are private by default.** Users must be logged in to access any endpoint unless explicitly marked as public. + +### Public Endpoints + +Mark an entire endpoint as publicly accessible: ```php +use Baraja\StructuredApi\Attributes\PublicEndpoint; + #[PublicEndpoint] final class ProductEndpoint extends BaseEndpoint { + public function actionDefault(): array + { + // Accessible without authentication + } } ``` -To restrict rights, define an `#[Role]` attribute over a class or method. +### Role-Based Access Control -For example (only administrators and moderators can call this endpoint): +Restrict access to specific user roles: ```php +use Baraja\StructuredApi\Attributes\Role; + #[Role(roles: ['admin', 'moderator'])] final class ArticleEndpoint extends BaseEndpoint { + // Only admin or moderator can access any method } ``` -Rights settings can also be combined. For example, in a public endpoint, restrict rights to a specific method only: +Restrict specific methods: ```php #[PublicEndpoint] -final class SitemapEndpoint extends BaseEndpoint +final class ArticleEndpoint extends BaseEndpoint +{ + public function actionDefault(): array + { + // Public access + } + + #[Role(roles: 'admin')] + public function actionDelete(int $id): void + { + // Only admin can delete + } + + #[Role(roles: ['admin', 'editor'])] + public function postCreate(string $title): ArticleResponse + { + // Admin or editor can create + } +} +``` + +### Permission Check Flow + +1. Check if endpoint has `#[PublicEndpoint]` attribute +2. If not public, require user to be logged in (returns 401 if not) +3. Check `#[Role]` attributes on class and method +4. If roles defined, verify user has at least one matching role (returns 403 if not) +5. If user is logged in and no roles required, allow access + +### Ignoring Default Permissions + +For special cases, you can disable the default permission checking: + +```php +$convention = $container->getByType(Convention::class); +$convention->setIgnoreDefaultPermission(true); +``` + +## :gear: Convention Configuration + +The `Convention` entity controls response formatting and behavior: + +```php +$convention = $container->getByType(Convention::class); + +// Date/time format for serialization (default: 'Y-m-d H:i:s') +$convention->setDateTimeFormat('c'); // ISO 8601 + +// Default HTTP codes +$convention->setDefaultErrorCode(500); +$convention->setDefaultOkCode(200); + +// Remove null values from response to reduce payload size +$convention->setRewriteNullToUndefined(true); + +// Keys to hide from response (sensitive data) +$convention->setKeysToHide([ + 'password', 'passwd', 'pass', 'pwd', + 'creditcard', 'credit card', 'cc', 'pin', + 'secret', 'token', +]); + +// Use __toString() method when serializing objects +$convention->setRewriteTooStringMethod(true); +``` + +## :electric_plug: Middleware Extensions + +Create custom middleware by implementing `MatchExtension`: + +```php +use Baraja\StructuredApi\Middleware\MatchExtension; +use Baraja\StructuredApi\Endpoint; +use Baraja\StructuredApi\Response; + +final class RateLimitExtension implements MatchExtension +{ + public function beforeProcess( + Endpoint $endpoint, + array $params, + string $action, + string $method, + ): ?Response { + if ($this->isRateLimited()) { + return new JsonResponse($this->convention, [ + 'state' => 'error', + 'message' => 'Rate limit exceeded', + ], 429); + } + + return null; // Continue processing + } + + public function afterProcess( + Endpoint $endpoint, + array $params, + ?Response $response, + ): ?Response { + // Modify or replace response after processing + return null; // Use original response + } +} +``` + +Register the extension: + +```php +$apiManager = $container->getByType(ApiManager::class); +$apiManager->addMatchExtension(new RateLimitExtension()); +``` + +## :telephone_receiver: Programmatic API Calls + +Call endpoints programmatically from PHP code: + +```php +$apiManager = $container->getByType(ApiManager::class); + +// Get response as array +$result = $apiManager->get('article/detail', ['id' => 123]); + +// With explicit HTTP method +$result = $apiManager->get('article/create', ['title' => 'New'], 'POST'); + +// The path is automatically prefixed with 'api/v1/' if not present +$result = $apiManager->get('api/v1/article/detail', ['id' => 123]); +``` + +## :link: URL Routing + +API URLs follow this pattern: + +``` +/api/v{version}/{endpoint}/{action}?{parameters} +``` + +### Examples + +| URL | Endpoint Class | Method Called | +|-----|----------------|---------------| +| `/api/v1/article` | `ArticleEndpoint` | `actionDefault()` | +| `/api/v1/article/detail?id=5` | `ArticleEndpoint` | `actionDetail(5)` | +| `/api/v1/user-profile` | `UserProfileEndpoint` | `actionDefault()` | +| `/api/v1/user-profile/settings` | `UserProfileEndpoint` | `actionSettings()` | + +### Naming Convention + +Endpoint class names are converted to URL paths using kebab-case: +- `ArticleEndpoint` → `/api/v1/article` +- `UserProfileEndpoint` → `/api/v1/user-profile` +- `MyAwesomeApiEndpoint` → `/api/v1/my-awesome-api` + +Action names also use kebab-case in URLs: +- `actionGetUserProfile()` → `/api/v1/endpoint/get-user-profile` + +## :busts_in_silhouette: User Management Integration + +The package integrates with [baraja-core/cas](https://github.com/baraja-core/cas) for user management: + +```php +final class ProfileEndpoint extends BaseEndpoint +{ + public function actionDefault(): UserResponse + { + // Check if user is logged in + if (!$this->isUserLoggedIn()) { + $this->sendError('Not authenticated', 401); + } + + // Get current user + $user = $this->getUser(); + + // Get user identity entity + $identity = $this->getUserEntity(); + + return new UserResponse($identity); + } +} +``` + +## :link: Link Generation + +Generate application links from endpoints: + +```php +final class ArticleEndpoint extends BaseEndpoint +{ + public function actionDetail(int $id): ArticleResponse + { + $article = $this->repository->find($id); + + return new ArticleResponse( + id: $article->getId(), + title: $article->getTitle(), + editUrl: $this->link('Admin:Article:edit', ['id' => $id]), + viewUrl: $this->linkSafe('Front:Article:detail', ['slug' => $article->getSlug()]), + ); + } +} +``` + +- `link()` - Generates link, throws exception if route doesn't exist +- `linkSafe()` - Returns `null` if route doesn't exist + +## :key: API Token Authentication + +For secure communication with external services or partners, use the official token authorizer extension: + +[structured-api-token-authorizer](https://github.com/baraja-core/structured-api-token-authorizator) + +## :book: Automatic Documentation + +Generate API documentation automatically from your endpoint code: + +[Structured API Documentation](https://github.com/baraja-core/structured-api-doc) + +This extension scans your endpoints and generates documentation based on: +- Method signatures and parameters +- PHPDoc annotations +- Return type DTOs +- Permission attributes + +## :test_tube: Built-in Test Endpoints + +The package includes two test endpoints for verification: + +### Ping Endpoint + +``` +GET /api/v1/ping +``` + +Response: +```json +{ + "result": "PONG", + "ip": "127.0.0.1", + "datetime": "2024-01-15 10:30:00" +} +``` + +### Test Endpoint + +``` +GET /api/v1/test?hello=World +``` + +Response: +```json +{ + "name": "Test API endpoint", + "hello": "World", + "endpoint": "Test" +} +``` + +## :warning: Error Handling + +The API automatically handles errors and returns appropriate HTTP codes: + +| HTTP Code | Situation | +|-----------|-----------| +| 200 | Successful request | +| 400 | Bad request (validation error) | +| 401 | Unauthorized (not logged in) | +| 403 | Forbidden (missing role) | +| 404 | Endpoint or action not found | +| 500 | Internal server error | + +Error response format: +```json { - #[Role(roles: 'admin')] - public function actionClearCache(): void - { - // your secured implementation - } + "state": "error", + "message": "Human readable error message", + "code": 500 } ``` -🔒 Check API token ------------------- +In debug mode (Tracy enabled), the `message` field contains the actual exception message. In production, a generic error message is shown for security. -If you want to provide the API to your external partners or to provide secure communication with another application, it is a good idea to use authentication of all requests via an API token. There is an official extension [structured-api-token-authorizer](https://github.com/baraja-core/structured-api-token-authorizator) for this use. +## :arrows_counterclockwise: CORS Support -🗺️ Project endpoint documentation ---------------------------------- +Cross-Origin Resource Sharing is automatically handled: -When developing a real application, you will often need to pass work between the backend and the frontend. +- `Access-Control-Allow-Origin` - Set to request origin +- `Access-Control-Allow-Credentials` - Enabled +- `Access-Control-Max-Age` - 86400 seconds (1 day) +- OPTIONS preflight requests are handled automatically -To describe all endpoints, the package offers an optional extension that generates documentation automatically based on real code scanning. +## :man_technologist: Author -Try the [Structured API Documentation](https://github.com/baraja-core/structured-api-doc). +**Jan Barasek** - [https://baraja.cz](https://baraja.cz) -📄 License ------------ +## :page_facing_up: License `baraja-core/structured-api` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/structured-api/blob/master/LICENSE) file for more details. From 5afe7e97566831a840880343dbb00fb61941863c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bar=C3=A1=C5=A1ek?= Date: Sun, 4 Jan 2026 11:28:51 +0100 Subject: [PATCH 3/3] Updated README.md --- README.md | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index cf70930..84ed7eb 100644 --- a/README.md +++ b/README.md @@ -31,51 +31,51 @@ A powerful, type-safe REST API framework for PHP 8.1+ with full Nette Framework The package follows a layered architecture with clear separation of concerns: ``` -┌─────────────────────────────────────────────────────────────────────┐ -│ HTTP Request │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ ApiManager │ -│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ -│ │ URL Router │ │ CORS Handler │ │ Tracy Panel │ │ -│ │ /api/v1/{path} │ │ (Preflight) │ │ (Debug) │ │ -│ └────────┬────────┘ └──────────────────┘ └───────────────────┘ │ -│ │ │ -│ ▼ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Middleware Pipeline │ │ -│ │ ┌─────────────────────┐ ┌──────────────────────────────┐ │ │ -│ │ │ PermissionExtension │ │ Custom MatchExtensions │ │ │ -│ │ │ (Auth & Roles) │ │ (beforeProcess/afterProcess)│ │ │ -│ │ └─────────────────────┘ └──────────────────────────────┘ │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ Endpoint │ -│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │ -│ │ BaseEndpoint │ │ Method Invoker │ │ Convention │ │ -│ │ (Your Logic) │ │ (Param Binding) │ │ (Formatting) │ │ -│ └────────┬────────┘ └──────────────────┘ └───────────────────┘ │ -│ │ │ -│ ▼ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Response System │ │ -│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │ │ -│ │ │DTO Objects │ │StatusResp │ │ JsonResponse │ │ │ -│ │ │(Your Types)│ │(Ok/Error) │ │ (Serialized) │ │ │ -│ │ └────────────┘ └────────────┘ └────────────────────────┘ │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ HTTP Response │ -│ (JSON with proper HTTP code) │ -└─────────────────────────────────────────────────────────────────────┘ +┌───────────────────────────────────────────────────────────────┐ +│ HTTP Request │ +└───────────────────────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────────┐ +│ ApiManager │ +│ ┌───────────────┐ ┌────────────────┐ ┌─────────────────┐ │ +│ │ URL Router │ │ CORS Handler │ │ Tracy Panel │ │ +│ │ /api/v1/{ep} │ │ (Preflight) │ │ (Debug) │ │ +│ └───────┬───────┘ └────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Middleware Pipeline │ │ +│ │ ┌───────────────────┐ ┌──────────────────────────┐ │ │ +│ │ │PermissionExtension│ │ Custom MatchExtensions │ │ │ +│ │ │ (Auth & Roles) │ │ (before/after process) │ │ │ +│ │ └───────────────────┘ └──────────────────────────┘ │ │ +│ └────────────────────────────────────────────────────────┘ │ +└───────────────────────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────────┐ +│ Endpoint │ +│ ┌───────────────┐ ┌────────────────┐ ┌─────────────────┐ │ +│ │ BaseEndpoint │ │ Method Invoker │ │ Convention │ │ +│ │ (Your Logic) │ │ (Param Binding)│ │ (Formatting) │ │ +│ └───────┬───────┘ └────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Response System │ │ +│ │ ┌────────────┐ ┌────────────┐ ┌──────────────────┐ │ │ +│ │ │DTO Objects │ │ StatusResp │ │ JsonResponse │ │ │ +│ │ │(Your Types)│ │ (Ok/Error) │ │ (Serialized) │ │ │ +│ │ └────────────┘ └────────────┘ └──────────────────┘ │ │ +│ └────────────────────────────────────────────────────────┘ │ +└───────────────────────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────────┐ +│ HTTP Response │ +│ (JSON with proper HTTP code) │ +└───────────────────────────────────────────────────────────────┘ ``` ### Core Components