monkeyscloud / monkeyslegion-openapi
Automatic OpenAPI 3.1 specification generator and Swagger UI middleware for the MonkeysLegion framework.
Package info
github.com/MonkeysCloud/MonkeysLegion-OpenApi
pkg:composer/monkeyscloud/monkeyslegion-openapi
Requires
- php: ^8.4
- monkeyscloud/monkeyslegion-http: ^2.0 || dev-2.x-dev as 1.99.x-dev
- monkeyscloud/monkeyslegion-router: ^2.0 || dev-main
- psr/http-message: ^2.0
- psr/http-server-middleware: ^1.0
Requires (Dev)
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-04-11 21:17:23 UTC
README
Automatic OpenAPI 3.1 specification generator and documentation middleware for the MonkeysLegion framework.
Generate a complete API specification from your route definitions and PHP 8.4 attributes — zero manual YAML/JSON editing required.
Features
| Feature | Description |
|---|---|
| Attribute-driven | Annotate controllers with #[ApiParam], #[ApiResponse], #[RequestBody], #[ApiSecurity], #[ApiDeprecated], #[ApiHidden] |
| Auto parameter detection | Path parameters like {id} are automatically documented |
| Security schemes | Bearer JWT, API key, OAuth2 — configurable per-controller or per-method |
| Multiple responses | Document 200, 404, 422, etc. with schemas per endpoint |
| Request body schemas | Inline JSON Schema or $ref to DTO classes |
| Swagger UI + ReDoc | Built-in middleware serves either documentation UI |
| Dark mode | Optional dark theme for Swagger UI |
| Caching | Spec is cached after first build; invalidate on demand |
| YAML export | toYaml() when ext-yaml is available |
| Enable/disable | Toggle docs off in production with a single flag |
Installation
composer require monkeyscloud/monkeyslegion-openapi
Requirements
- PHP 8.4+
monkeyscloud/monkeyslegion-router^2.0monkeyscloud/monkeyslegion-http^2.0
Quick Start
1. Annotate your controller
<?php declare(strict_types=1); namespace App\Controllers; use MonkeysLegion\OpenApi\Attributes\ApiInfo; use MonkeysLegion\OpenApi\Attributes\ApiParam; use MonkeysLegion\OpenApi\Attributes\ApiResponse; use MonkeysLegion\OpenApi\Attributes\ApiSecurity; use MonkeysLegion\OpenApi\Attributes\RequestBody; use MonkeysLegion\Router\Attributes\Route; #[ApiInfo( title: 'User Service API', version: '2.0.0', description: 'Manages user accounts and profiles.', contactName: 'MonkeysCloud Team', contactEmail: 'support@monkeys.cloud', )] #[ApiSecurity('bearerAuth')] final class UserController { #[Route('GET', '/users', name: 'user_list', summary: 'List users', tags: ['Users'])] #[ApiParam(name: 'page', in: 'query', type: 'integer', example: 1)] #[ApiParam(name: 'per_page', in: 'query', type: 'integer', example: 25, required: false)] #[ApiResponse(200, 'User list', schema: [ 'type' => 'array', 'items' => ['$ref' => '#/components/schemas/User'], ])] public function index(): ResponseInterface { /* ... */ } #[Route('GET', '/users/{id:\d+}', name: 'user_show', summary: 'Get user', tags: ['Users'])] #[ApiParam(name: 'id', in: 'path', type: 'integer')] #[ApiResponse(200, 'User found')] #[ApiResponse(404, 'User not found')] public function show(int $id): ResponseInterface { /* ... */ } #[Route('POST', '/users', name: 'user_create', summary: 'Create user', tags: ['Users'])] #[RequestBody( description: 'User creation payload', schema: [ 'type' => 'object', 'properties' => [ 'name' => ['type' => 'string'], 'email' => ['type' => 'string', 'format' => 'email'], ], 'required' => ['name', 'email'], ], )] #[ApiResponse(201, 'User created')] #[ApiResponse(422, 'Validation error')] public function create(): ResponseInterface { /* ... */ } }
2. Register the middleware
use MonkeysLegion\OpenApi\OpenApiGenerator; use MonkeysLegion\OpenApi\OpenApiMiddleware; $generator = new OpenApiGenerator( routes: $routeCollection, title: 'My API', version: '1.0.0', servers: [ ['url' => 'https://api.example.com', 'description' => 'Production'], ['url' => 'http://localhost:8080', 'description' => 'Local'], ], ); // Add to your middleware pipeline $handler->pipe(new OpenApiMiddleware( generator: $generator, jsonPath: '/openapi.json', // JSON spec endpoint uiPath: '/docs', // Swagger UI / ReDoc endpoint uiTheme: 'swagger', // 'swagger' or 'redoc' darkMode: false, // dark Swagger UI theme enabled: true, // set false in production ));
3. Access your docs
- JSON spec:
GET /openapi.json - Swagger UI:
GET /docs
Attributes Reference
#[ApiInfo] — Controller class
Defines API-level metadata. Place on the controller class.
#[ApiInfo(
title: 'My API',
version: '2.0.0',
description: 'API description',
contactName: 'Team',
contactEmail: 'team@example.com',
contactUrl: 'https://example.com',
licenseName: 'MIT',
licenseUrl: 'https://opensource.org/licenses/MIT',
termsOfService: 'https://example.com/tos',
)]
#[ApiParam] — Method (repeatable)
Documents a path, query, header, or cookie parameter.
#[ApiParam(
name: 'id',
in: 'path', // 'path', 'query', 'header', 'cookie'
type: 'integer', // JSON Schema type
format: 'int64', // JSON Schema format
required: true,
description: 'The user ID',
example: 42,
deprecated: false,
)]
Note: Path parameters from route templates (e.g.,
{id}) are auto-detected if not explicitly annotated.
#[ApiResponse] — Method (repeatable)
Documents a response for a specific status code.
#[ApiResponse(
status: 200,
description: 'Success',
contentType: 'application/json',
schema: ['type' => 'object', 'properties' => [...]],
headers: ['X-Request-Id' => ['schema' => ['type' => 'string']]],
)]
#[RequestBody] — Method
Documents the request body and its schema.
#[RequestBody(
description: 'User data',
required: true,
contentType: 'application/json',
schema: ['type' => 'object', ...],
ref: App\DTO\CreateUserDto::class, // alternative: reference a DTO
)]
#[ApiSecurity] — Class or Method (repeatable)
Declares security requirements.
#[ApiSecurity('bearerAuth')] #[ApiSecurity('oauth2', scopes: ['users:read', 'users:write'])]
#[ApiDeprecated] — Method
Marks an endpoint as deprecated in the spec.
#[ApiDeprecated('Use PATCH /v2/users/{id} instead.')]
#[ApiHidden] — Method
Excludes an endpoint from the generated specification entirely.
#[ApiHidden]
Generator API
$generator = new OpenApiGenerator( routes: $routeCollection, title: 'My API', version: '1.0.0', description: 'Optional description', servers: [['url' => 'https://api.example.com']], securitySchemes: [ 'bearerAuth' => [ 'type' => 'http', 'scheme' => 'bearer', 'bearerFormat' => 'JWT', ], 'apiKey' => [ 'type' => 'apiKey', 'in' => 'header', 'name' => 'X-API-Key', ], ], ); // Get as PHP array $spec = $generator->toArray(); // Get as JSON $json = $generator->toJson(); // Get as YAML (requires ext-yaml) $yaml = $generator->toYaml(); // Clear cached spec $generator->invalidate();
Middleware Options
| Parameter | Type | Default | Description |
|---|---|---|---|
generator |
OpenApiGenerator |
— | Required. The spec generator. |
jsonPath |
string |
/openapi.json |
URI path for the JSON spec. |
uiPath |
string |
/docs |
URI path for the documentation UI. |
uiTheme |
string |
'swagger' |
'swagger' or 'redoc'. |
darkMode |
bool |
false |
Enable dark Swagger UI theme. |
enabled |
bool |
true |
Set false to disable docs in production. |
Testing
composer test
31 tests, 69 assertions covering:
- Spec generation (version, info, paths, operations)
- All 7 attributes
- Parameter auto-detection
- Request body, responses, security, deprecated, hidden
- Middleware (Swagger UI, ReDoc, passthrough, disabled)
- Caching and invalidation
License
MIT © MonkeysCloud