Installation:
composer require draw/open-api-bundle
Add the bundle to config/bundles.php:
return [
// ...
Draw\OpenApiBundle\DrawOpenApiBundle::class => ['all' => true],
];
First Use Case: Annotate a controller method to generate OpenAPI v2 documentation:
use OpenApi\Annotations as OA;
class UserController extends AbstractController
{
/**
* @OA\Get(
* path="/users/{id}",
* summary="Get a user",
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="User details",
* @OA\JsonContent(ref="#/definitions/User")
* )
* )
*/
public function getUser(int $id): JsonResponse
{
// ...
}
}
Generate Documentation:
bin/console draw:open-api:generate
Output will be saved to public/api-docs.json.
Documenting Controllers:
Use @OA\* annotations to define endpoints, parameters, responses, and schemas.
Example for POST with request body:
/**
* @OA\Post(
* path="/users",
* summary="Create a user",
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(ref="#/definitions/User")
* ),
* @OA\Response(
* response=201,
* description="User created",
* @OA\JsonContent(ref="#/definitions/User")
* )
* )
*/
Reusing Schemas:
Define schemas in a separate file (e.g., src/OpenApi/Schemas/User.php) and reference them:
namespace App\OpenApi\Schemas;
use OpenApi\Annotations as OA;
/**
schema="User",
required={"name", "email"},
@OA\Property(property="id", type="integer"),
@OA\Property(property="name", type="string"),
@OA\Property(property="email", type="string", format="email")
Doctrine Integration: Enable auto-detection of Doctrine entities for schema generation:
draw_open_api:
enableDoctrineSupport: true
Annotate entities to generate schemas automatically:
/**
* @OA\Schema()
*/
class User {}
REST API Without FOSRest: Use the bundle’s built-in response converters to serialize entities:
use Draw\OpenApiBundle\Serializer\OpenApiResponse;
public function getUser(int $id): OpenApiResponse
{
return $this->openApiResponse(new User());
}
symfony/serializer is installed for response conversion.api-docs.json via a route and integrate with Swagger UI.Draw\Component\OpenApi\Extractor\ExtractorInterface.Doctrine Auto-Detection:
enableDoctrineSupport is null, the bundle auto-detects Doctrine, but this may fail in complex setups (e.g., multiple Doctrine instances). Explicitly set true/false if issues arise.Circular References:
User hasMany Post, Post belongsTo User) may cause infinite recursion in schema generation. Use @OA\Property(ref="#/definitions/User") to break cycles.Annotation Parsing:
bin/console draw:open-api:generate after changes, not during runtime.Response Conversion:
responseConverter option (false by default) requires symfony/serializer and proper normalization logic. Enable it only if you’ve configured serializers for your entities.bin/console draw:open-api:generate --raw to inspect the generated OpenAPI spec without formatting.bin/console debug:container draw.open_api.extractor to list available extractors and debug issues.APP_DEBUG=1) to see detailed extraction logs.convertQueryParameterToAttribute:
true, query parameters (e.g., ?filter[name]=John) are converted to attributes in the schema. Useful for filtering but may not align with your API design.definitionAliases:
App\Entity\User → User). Ensure aliases are unique and don’t conflict with built-in OpenAPI definitions.Sandbox Installation:
draw:open-api:install-sandbox) installs a local copy of draw/open-api for testing. Avoid using it in production; prefer stable Composer versions.Custom Annotations:
Extend the bundle by creating custom annotations and registering them with the AnnotationExtractor.
Example:
// src/OpenApi/Annotation/CustomAnnotation.php
namespace App\OpenApi\Annotation;
use OpenApi\Annotations as OA;
#[Attribute]
class CustomAnnotation extends OA\Annotation {}
Event Listeners:
Subscribe to draw.open_api.generate events to modify the spec dynamically:
// src/EventListener/OpenApiListener.php
namespace App\EventListener;
use Draw\Component\OpenApi\Event\GenerateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OpenApiListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
GenerateEvent::class => 'onGenerate',
];
}
public function onGenerate(GenerateEvent $event): void
{
$event->getSpec()->info->title = 'My Custom API';
}
}
Schema Factories:
Override schema generation for specific classes by implementing Draw\Component\OpenApi\Factory\SchemaFactoryInterface.
How can I help you explore Laravel packages today?