Installation Add the package via Composer:
composer require api-platform/openapi
Ensure api-platform/core is installed (this package is a dependency).
First Use Case Generate an OpenAPI (Swagger) schema for your API Platform resources:
use ApiPlatform\OpenApi\Model;
use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
class CustomOpenApiFactory implements OpenApiFactoryInterface
{
public function __invoke(array $context = []): Model
{
$openapi = new Model();
$openapi->info = new Model\Info(
title: 'My API',
version: '1.0.0'
);
// Add paths, components, etc.
return $openapi;
}
}
Register the Factory
Bind the factory in config/services.php:
'api_platform.openapi.factory' => \App\OpenApi\CustomOpenApiFactory::class,
Access the Schema Fetch the OpenAPI schema via a controller or route:
use Symfony\Component\HttpFoundation\Response;
return new Response(
json_encode($this->openApiFactory(), JSON_PRETTY_PRINT),
Response::HTTP_OK,
['Content-Type' => 'application/json']
);
Extending Default Schema
Override or extend the default OpenAPI schema by implementing OpenApiFactoryInterface:
$openapi = $this->decorated->__invoke($context);
$openapi->paths->paths['/custom-endpoint'] = new Model\PathItem(...);
return $openapi;
Dynamic Schema Generation
Use the $context array to dynamically adjust the schema based on runtime conditions (e.g., environment, user roles):
if ($context['env'] === 'production') {
$openapi->servers = [new Model\Server(url: 'https://api.prod.example.com')];
}
Integrating with API Platform
Leverage ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface to fetch resource metadata and auto-generate paths, schemas, and operations:
$resourceMetadataFactory = app(ResourceMetadataFactoryInterface::class);
$resourceMetadata = $resourceMetadataFactory->create('App\Entity\Book');
$openapi->paths->paths['/api/books'] = new Model\PathItem(
get: new Model\Operation(ref: '#/components/responses/Book.getCollection')
);
Custom Components
Define reusable components (schemas, responses, parameters) in the components section:
$openapi->components = new Model\Components(
schemas: [
'Book' => new Model\Schema(ref: '#/components/schemas/Book'),
],
responses: [
'BookNotFound' => new Model\Response(ref: '#/components/responses/BookNotFound'),
]
);
Security Schemes Add OAuth2, API keys, or other security schemes:
$openapi->components->securitySchemes = [
'api_key' => new Model\SecurityScheme(
type: 'apiKey',
in: 'header',
name: 'X-API-KEY'
),
];
Server Configuration Define multiple servers (e.g., dev/staging/prod):
$openapi->servers = [
new Model\Server(url: 'https://api.dev.example.com'),
new Model\Server(url: 'https://api.prod.example.com'),
];
Symfony Flex Auto-configuration
The package auto-registers with API Platform if both are installed. Override via config/packages/api_platform.yaml:
api_platform:
openapi:
enabled: true
context:
version: '1.0.0'
Caching Cache the generated OpenAPI schema to avoid regenerating it on every request:
$cache = new \Symfony\Component\Cache\SimpleFileCache('/path/to/cache');
$openapi = $cache->get('openapi_schema', function() use ($context) {
return $this->openApiFactory()($context);
});
Testing Test schema generation in PHPUnit:
$this->assertArrayHasKey('paths', $openapi->toArray());
$this->assertEquals('1.0.0', $openapi->info->version);
Schema Validation
$openapi->setStrictValidation(true);
Circular References
$ref fields (e.g., Book schema referencing itself). Use $ref sparingly or break cycles with inline schemas.Deprecated Features
x- extensions. Replace with extensions or vendor-specific prefixes (e.g., x-api-platform).Performance Overhead
API Platform Version Mismatch
api-platform/core and api-platform/openapi. Check the API Platform docs for version-specific quirks.Inspect Raw Output Dump the raw schema to debug:
dd($this->openApiFactory()->toArray());
Enable Verbose Logging Configure Monolog to log schema generation:
$logger = new \Monolog\Logger('openapi');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('/tmp/openapi.log', \Monolog\Logger::DEBUG));
Partial Schema Generation Generate only specific parts of the schema (e.g., paths) for debugging:
$openapi = $this->openApiFactory();
dd($openapi->paths->toArray());
Decorators Use Symfony’s decorator pattern to layer custom logic:
# config/services.yaml
App\OpenApi\CustomOpenApiDecorator:
decorates: 'api_platform.openapi.factory'
arguments: ['@App\OpenApi\CustomOpenApiDecorator.inner']
Event Listeners
Listen to kernel.request to modify the schema dynamically:
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
$event->getRequest()->attributes->set('openapi_context', ['custom_key' => 'value']);
Custom Model Classes
Extend ApiPlatform\OpenApi\Model classes to add custom fields or validation:
class CustomInfo extends Model\Info
{
public string $customField;
}
CLI Generation Generate schemas via a console command for offline use:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class GenerateOpenApiCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$schema = $this->openApiFactory();
file_put_contents('openapi.json', json_encode($schema->toArray()));
return Command::SUCCESS;
}
}
Context Overrides
The $context array passed to the factory can override default values. Ensure consistency:
$openapi = $this->openApiFactory(['version' => '2.0.0']);
Resource Metadata Caching API Platform caches resource metadata. Clear the cache if schema changes aren’t reflected:
php bin/console cache:clear
OpenAPI Version Defaults to OpenAPI 3.1.0. Downgrade if needed:
$openapi->setVersion('3.0.0');
How can I help you explore Laravel packages today?