a5sys/apiplatform-typescript-generator-bundle
Installation Add the bundle via Composer (if available in a public repo or manually cloned):
composer require a5sys/apiplatform-typescript-generator-bundle
If not published, clone the repo and require it locally:
composer require [email protected]:A5sys/ApiPlatformTypescriptGeneratorBundle.git
Enable the Bundle
Register the bundle in config/bundles.php:
return [
// ...
A5sys\ApiPlatformTypescriptGeneratorBundle\ApiPlatformTypescriptGeneratorBundle::class => ['all' => true],
];
Configure the Generator
Publish the default config (if available) and adjust in config/packages/a5sys_apiplatform_typescript_generator.yaml:
php bin/console config:dump-reference | grep a5sys_apiplatform_typescript_generator
Example minimal config:
a5sys_apiplatform_typescript_generator:
output_dir: '%kernel.project_dir%/client/src/generated'
format: 'typescript'
include: ['App\Entity']
exclude: []
First Use Case: Generate API Types Run the generator command to scaffold TypeScript interfaces/models:
php bin/console a5sys:apiplatform:generate
Verify output in client/src/generated/ (adjust output_dir as needed).
Integrate with API Platform Resources
Ensure your API Platform resources (e.g., src/Entity/Book.php) are annotated with @ApiResource:
use ApiPlatform\Core\Annotation\ApiResource;
#[ApiResource]
class Book {}
The generator will pick up these entities automatically (based on include/exclude config).
Customize Output Structure Use Twig templates to modify generated files. Override the default template path:
a5sys_apiplatform_typescript_generator:
template: '%kernel.project_dir%/templates/typescript/generated.twig'
Example template snippet:
{# client/src/generated/Book.ts #}
export interface Book {
{# Loop through properties #}
{% for property, type in properties %}
{{ property }}: {{ type }};
{% endfor %}
}
Incremental Generation
Use --force to overwrite existing files or --dry-run to preview changes:
php bin/console a5sys:apiplatform:generate --force
php bin/console a5sys:apiplatform:generate --dry-run
Hook into Build Process
Add the command to your composer.json scripts for CI/CD:
"scripts": {
"post-autoload-dump": [
"php bin/console a5sys:apiplatform:generate --force"
]
}
Frontend Framework Compatibility Generate types for React/Vue by extending the output template to include hooks/lifecycle methods:
export interface BookState {
data: Book | null;
loading: boolean;
error: string | null;
}
API Platform Extensions For custom serializers/validators, ensure the generator accounts for them by extending the metadata parser:
a5sys_apiplatform_typescript_generator:
metadata_parser: 'App\Service\CustomMetadataParser'
Monorepo Setups
Use symlinks or absolute paths in output_dir to share generated types across frontend/backend repos.
POC Limitations
Configuration Quirks
include/exclude arrays use class names as strings (e.g., ['App\Entity\Book']), not objects.--force to replace them.Debugging
--dry-run before committing:
php bin/console a5sys:apiplatform:generate --dry-run -v
output_dir for partial files if the command fails silently.exclude rules are blocking them.Custom Metadata Parsing Override the default parser to handle custom attributes or logic:
// src/Service/CustomMetadataParser.php
namespace App\Service;
use A5sys\ApiPlatformTypescriptGeneratorBundle\Parser\MetadataParserInterface;
class CustomMetadataParser implements MetadataParserInterface {
public function parse(object $entity): array {
// Add custom logic (e.g., for @Groups from ApiPlatform\Metadata\ApiResource)
return [
'properties' => [
'id' => 'number',
// ...
],
];
}
}
Register it in config:
a5sys_apiplatform_typescript_generator:
metadata_parser: 'App\Service\CustomMetadataParser'
Post-Generation Hooks Use Symfony’s event system to modify files after generation. Example listener:
// src/EventListener/GenerateTypesListener.php
namespace App\EventListener;
use A5sys\ApiPlatformTypescriptGeneratorBundle\Event\TypesGeneratedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class GenerateTypesListener implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
TypesGeneratedEvent::class => 'onTypesGenerated',
];
}
public function onTypesGenerated(TypesGeneratedEvent $event) {
$files = $event->getGeneratedFiles();
foreach ($files as $path => $content) {
// Modify content (e.g., add imports)
$files[$path] = "import { BaseEntity } from './BaseEntity';\n" . $content;
}
$event->setGeneratedFiles($files);
}
}
Handling Complex Types For relationships or collections, extend the template to generate nested interfaces:
{# For a Book with Author relationship #}
export interface Book {
title: string;
author: Author; {# Nested interface #}
}
export interface Author {
name: string;
}
Ensure your metadata_parser resolves these relationships correctly.
composer.json to avoid unexpected updates:
"require": {
"a5sys/apiplatform-typescript-generator-bundle": "dev-main"
}
export interface Book {
{# Fallback to 'any' if type is unknown #}
{% for property, type in properties|default({}) %}
{{ property }}: {{ type|default('any') }};
{% endfor %}
}
How can I help you explore Laravel packages today?