The OpenAPI Command Bundle is a Symfony bundle that allows you to build HTTP APIs around Command Bus messages (DTOs) without the need for manual controller creation or Symfony #[Route] attributes on your commands.
By using standard OpenAPI operation attributes (from zircote/swagger-php) directly on your command DTOs, this bundle automatically generates Symfony routes and handles the entire request-to-command lifecycle: deserialization, validation, dispatching to the messenger bus, and responding.
- OpenAPI-Driven Routing: Define your API endpoints directly on your command DTOs using
#[OA\Post],#[OA\Get],#[OA\Put], etc. - No Manual Controllers: A single
CommandControllerhandles all generated routes by default. - Automatic Deserialization: Automatically maps JSON request bodies, route parameters, and query parameters to your command DTOs.
- Built-in Validation: Integrates with Symfony Validator to ensure your commands are valid before they reach your handlers.
- Messenger Integration: Dispatches your commands directly to the Symfony Messenger bus.
- Auto-Generated Documentation: Seamlessly integrates with
NelmioApiDocBundleto include your command-based routes in your OpenAPI/Swagger documentation. - Problem Details Support: Returns RFC 7807 compliant error responses for validation and mapping errors.
composer require stixx/openapi-command-bundleIf you are using Symfony Flex, the bundle will be automatically enabled. Otherwise, add it to your config/bundles.php:
return [
// ...
Stixx\OpenApiCommandBundle\StixxOpenApiCommandBundle::class => ['all' => true],
];Annotate your command with OpenAPI attributes. No Symfony #[Route] is needed.
namespace App\Command;
use OpenApi\Attributes as OA;
use Symfony\Component\Validator\Constraints as Assert;
#[OA\Post(
path: '/api/projects',
operationId: 'create_project',
summary: 'Create a new project'
)]
final class CreateProjectCommand
{
public function __construct(
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 50)]
public string $name,
#[Assert\Length(max: 255)]
public ?string $description = null,
) {}
}Implement a standard Symfony Messenger handler for your command.
namespace App\Handler;
use App\Command\CreateProjectCommand;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
final class CreateProjectHandler
{
public function __invoke(CreateProjectCommand $command): array
{
// Your business logic here (e.g., persist to database)
return [
'id' => '123',
'name' => $command->name,
];
}
}The bundle automatically registers the route /api/projects (POST).
curl -X POST http://localhost:3000/api/projects \
-H "Content-Type: application/json" \
-d '{"name": "New Project", "description": "This is a project description"}'The bundle will:
- Detect the route and map it to
CreateProjectCommand. - Deserialize the JSON body into the command object.
- Validate the command using Symfony Validator.
- Dispatch the command to the Messenger bus.
- Return the handler's result as a JSON response with an appropriate status code (e.g.,
201 Created).
You can customize the bundle's behavior in config/packages/stixx_openapi_command.yaml:
stixx_openapi_command:
validation:
enabled: true
groups: ['Default']
openapi:
problem_details: true # Enable RFC 7807 problem details for errorsFor more detailed information, please refer to the following documentation:
- PHP 8.4 or higher
- Symfony 7.3 or higher
This bundle is released under the MIT License.