monkeyscloud/monkeyslegion-openapi

Automatic OpenAPI 3.1 specification generator and Swagger UI middleware for the MonkeysLegion framework.

Maintainers

Package info

github.com/MonkeysCloud/MonkeysLegion-OpenApi

pkg:composer/monkeyscloud/monkeyslegion-openapi

Statistics

Installs: 12

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-04-10 21:18 UTC

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.0
  • monkeyscloud/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