Skip to main content

How it Works

The generator leverages the existing framework infrastructure to discover and process your API metadata:
  1. Route Discovery: It uses the Router to find all registered routes and their corresponding controller classes.
  2. Metadata Extraction: For each discovered route, it calls:
    • AbstractApivalkController::getRequestDocumentation()
    • AbstractApivalkController::getResponseDocumentation()
  3. Object Mapping: It maps the Apivalk Property system to OpenAPI objects (Schemas, Parameters, RequestBodies, Responses).
  4. Serialization: It assembles these objects into a final OpenAPI object and serializes it to JSON.

Core Logic

The OpenAPI Object

The OpenAPI class represents the root of the specification. It contains sub-objects for:
  • InfoObject: API title, version, description.
  • ServerObject: Base URLs for your API.
  • PathsObject: Map of endpoints and their methods.
  • ComponentsObject: Reusable schemas and security schemes.

The Generation Process

The OpenAPIGenerator coordinates several specialized generators:
  • PathsGenerator: Processes the list of routes.
  • PathItemGenerator: Handles a single URL (which may have multiple HTTP methods).
  • OperationGenerator: Handles a single HTTP method (GET, POST, etc.) on a path.
  • ParameterGenerator: Converts query and path properties to OpenAPI parameters.
  • RequestBodyGenerator: Converts body properties to a JSON request body schema.
  • ResponseGenerator: Converts response documentation to OpenAPI response schemas.

Usage Example

use apivalk\apivalk\Documentation\OpenAPI\OpenAPIGenerator;
use apivalk\apivalk\Documentation\OpenAPI\Object\InfoObject;
use apivalk\apivalk\Documentation\OpenAPI\Object\ComponentsObject;
use apivalk\apivalk\Documentation\OpenAPI\Object\SecuritySchemeObject;
use apivalk\apivalk\Documentation\OpenAPI\Object\ServerObject;

// 1. Define API Metadata
$info = new InfoObject('My nice api', '1.0.0', 'Nice', 'Best API in ze world');

// 2. Define Components (e.g., Security Schemes)
$components = new ComponentsObject();
$components->setSecuritySchemes([
    'bearerAuth' => new SecuritySchemeObject(
        'http',
        'bearerAuth',
        'Standard Bearer Authentication',
        null,
        'bearer',
        'JWT',
        null,
        null
    ),
    'oauth2' => new SecuritySchemeObject(
        'oauth2',
        'oauth2',
        'OAuth2 Authentication',
        null,
        null,
        null,
        new OAuthFlowsObject(
            null,
            new OAuthFlowObject(
                'https://example.com/api/oauth/authorize',
                'https://example.com/api/oauth/token',
                'https://example.com/api/oauth/refresh',
                [
                    'read' => 'Read access',
                    'write' => 'Write access'
                ]
            ),
            null,
            null
        ),
        null
    ),
    'fido' => new SecuritySchemeObject(
        'apiKey',
        'fido',
        'FIDO/WebAuthn Authentication',
        'header',
        null,
        null,
        null,
        null
    )
]);

// 3. Instantiate the Generator
$generator = new OpenAPIGenerator(
    $apivalk, 
    $info, 
    [new ServerObject('http://localhost:8080', 'My local server')],
    $components
);

// 4. Generate the JSON string
$json = $generator->generate('json');

// 5. Output or save to file
header('Content-Type: application/json');
echo $json;

Security Schemes and Components

The ComponentsObject is where you define reusable elements for your OpenAPI specification, such as security schemes, common schemas, or parameters.

Automatic Security Scheme Generation

If you use security requirements in your routes but haven’t defined them in the ComponentsObject, the OpenAPIGenerator will attempt to automatically generate a base authorization part for you:
  • If the scheme name contains “bearer”, it defaults to an http type with a bearer scheme.
  • If the scheme name contains “oauth2”, it defaults to an oauth2 type with a basic password flow.
  • If the scheme name contains “fido”, it defaults to an apiKey type in the header.
  • Otherwise, it defaults to an apiKey type in the header.

Best Practice: Explicit Definition

While automatic generation works for simple cases, it is highly recommended to explicitly define your security schemes when initializing the OpenAPIGenerator. By defining your own SecuritySchemeObject in the ComponentsObject, you gain full control over the documentation. This is especially important for complex schemes like OAuth2, where you can define OAuthFlows (authorization URLs, token URLs, scopes). This allows tools like Swagger UI to provide a functional “Authorize” button that works instantly with your authentication provider. Crucially, the name you use in your routes (RouteAuthorization) must match the key used in ComponentsObject::setSecuritySchemes().
Keep in mind: Future Auto-Discovery. Apivalk is moving towards full auto-discovery of security schemes. In the future, it will be able to automatically detect and document your security configuration (including names and versions) directly from your middleware and authenticators.
$components = new ComponentsObject();
$components->setSecuritySchemes([
    'BearerAuth' => new SecuritySchemeObject(
        'http',
        'BearerAuth', // This name should match the key
        'Standard JWT Bearer Authentication',
        null,
        'bearer',
        'JWT',
        null,
        null
    )
]);

// In your route:
$route = Route::post('/orders')->description('Create order')->authorization('BearerAuth', ['write:orders'])
Passing your custom components to the generator:
$generator = new OpenAPIGenerator(
    $apivalk,
    $info,
    $servers,
    $components // Pass your custom components here
);

Automated Pagination Envelope

If a response documentation has setHasResponsePagination(true), the generator automatically wraps the properties in a standard pagination envelope containing data, total, page, limit, etc.