schmunk42 / api-platform-utils-bundle
Generic utilities for API Platform projects: UUID resolver, credential encryption, OpenAPI enhancements, and Hydra operations
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/schmunk42/api-platform-utils-bundle
Requires
- php: >=8.2
- ext-sodium: *
- api-platform/core: ^3.0|^4.0
- doctrine/orm: ^2.0|^3.0
- psr/log: ^3.0
- symfony/config: ^7.0
- symfony/dependency-injection: ^7.0
- symfony/event-dispatcher: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/http-kernel: ^7.0
- symfony/uid: ^7.0
README
Generic utilities for API Platform projects: UUID resolver, credential encryption, OpenAPI enhancements, and Hydra operations.
Features
- UUID Resolver: Find entities by full or partial UUID (supports both binary and string UUID storage)
- Credential Encryption: Secure encryption/decryption using libsodium (XChaCha20-Poly1305)
- Relation Field Schema Decorator: Automatically adds x-* metadata to OpenAPI schemas for admin UI autocomplete
- Hydra Operations Subscriber: Enriches JSON-LD responses with operation metadata for better API discoverability
Installation
1. Add to composer.json
Since this is an internal bundle in the extensions/ directory, add autoloading:
{
"autoload": {
"psr-4": {
"Schmunk42\\ApiPlatformUtils\\": "extensions/api-platform-utils-bundle/src/"
}
}
}
Run composer dump-autoload:
composer dump-autoload
2. Register Bundle
Add to config/bundles.php:
return [ // ... Schmunk42\ApiPlatformUtils\Schmunk42ApiPlatformUtilsBundle::class => ['all' => true], ];
3. Configure
Create config/packages/schmunk42_api_platform_utils.yaml:
schmunk42_api_platform_utils: # Credential Encryption (required) credential_encryption: key: '%env(base64:CREDENTIALS_ENCRYPTION_KEY)%' # Relation Field Schema Decorator (optional) relation_field_decorator: api_prefix: '/api' decoration_priority: 10 label_property_candidates: - name - title - label - displayName # Hydra Operations (optional) hydra_operations: api_prefix: '/api' event_priority: -10
4. Set Environment Variable
Add to .env:
# Generate with: docker compose exec php bin/console app:generate-encryption-key CREDENTIALS_ENCRYPTION_KEY="base64-encoded-32-byte-key-here"
Usage
1. UUID Resolver
Find entities by full or partial UUID:
use Schmunk42\ApiPlatformUtils\Service\UuidResolver; class MyCommand extends Command { public function __construct( private readonly UuidResolver $uuidResolver ) { parent::__construct(); } protected function execute(InputInterface $input, OutputInterface $output): int { // Find by full UUID $entity = $this->uuidResolver->findByPartialUuid( Project::class, '550e8400-e29b-41d4-a716-446655440000' ); // Find by partial UUID (first 8 characters) $entity = $this->uuidResolver->findByPartialUuid( Project::class, '550e8400' ); if ($entity === null) { $output->writeln('Entity not found'); return Command::FAILURE; } return Command::SUCCESS; } }
Features:
- Supports binary UUID storage (BINARY(16) with Symfony Uid)
- Supports string UUID storage (CHAR(36) / GUID)
- Throws exception if partial UUID is ambiguous
- Automatically detects storage type from Doctrine metadata
2. Credential Encryption
Securely encrypt/decrypt API credentials:
use Schmunk42\ApiPlatformUtils\Service\CredentialEncryption; class MyService { public function __construct( private readonly CredentialEncryption $encryption ) {} public function store(array $credentials): string { // Encrypt credentials return $this->encryption->encrypt([ 'username' => 'user@example.com', 'password' => 'secret123', 'api_token' => 'token_abc123' ]); } public function retrieve(string $encryptedData): array { // Decrypt credentials try { return $this->encryption->decrypt($encryptedData); } catch (\RuntimeException $e) { // Decryption failed return []; } } }
Generate Encryption Key:
use Schmunk42\ApiPlatformUtils\Service\CredentialEncryption; // Generate a new base64-encoded 32-byte key $key = CredentialEncryption::generateKey(); echo "CREDENTIALS_ENCRYPTION_KEY=" . $key;
Security Features:
- Uses PHP's built-in libsodium (XChaCha20-Poly1305)
- Automatic nonce generation
- Memory cleanup with sodium_memzero
- Base64 encoding for storage
3. Relation Field Schema Decorator
Automatically enhances OpenAPI schemas for Doctrine relations. No code required!
Example Entity:
use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ApiResource] class Project { #[ORM\ManyToOne(targetEntity: Customer::class)] private ?Customer $customer = null; }
Generated OpenAPI Schema:
{
"Project": {
"properties": {
"customer": {
"type": ["string", "null"],
"format": "iri-reference",
"x-collection": "/api/admin/customers",
"x-label-property": "name",
"x-value-property": "@id",
"x-search-property": "name",
"x-resource-class": "Customer"
}
}
}
}
What it does:
- Detects all Doctrine relations (ManyToOne, OneToOne, ManyToMany)
- Adds x-collection URL for autocomplete endpoints
- Infers label property from entity (checks: name, title, label, displayName)
- Only applies to INPUT schemas (forms, not responses)
- Configurable API prefix and label property candidates
Use in Admin UI: The x-* extensions are used by admin UIs (like API Platform Admin) to render autocomplete dropdowns for relation fields.
4. Hydra Operations Subscriber
Automatically adds operation metadata to JSON-LD item responses. No code required!
Before (Standard JSON-LD response):
{
"@id": "/api/admin/projects/550e8400",
"@type": "Project",
"name": "My Project"
}
After (With hydra:operation):
{
"@id": "/api/admin/projects/550e8400",
"@type": "Project",
"name": "My Project",
"hydra:operation": [
{
"@id": "/api/admin/projects/550e8400",
"@type": "hydra:Operation",
"method": "GET",
"title": "Retrieves a Project resource",
"returns": "Project"
},
{
"@id": "/api/admin/projects/550e8400",
"@type": "hydra:Operation",
"method": "PUT",
"title": "Replaces the Project resource",
"expects": "Project",
"returns": "Project"
},
{
"@id": "/api/admin/projects/550e8400/health",
"@type": "hydra:Operation",
"method": "GET",
"title": "Health",
"returns": "Project"
}
]
}
What it does:
- Adds complete list of available operations to each item response
- Includes standard CRUD operations and custom operations
- Generates human-readable titles for operations
- Adds expects/returns schema information
- Makes API self-documenting and discoverable
Configuration Reference
schmunk42_api_platform_utils: credential_encryption: enabled: true # Enable/disable credential encryption service key: '%env(base64:CREDENTIALS_ENCRYPTION_KEY)%' # Required: 32-byte base64-encoded key relation_field_decorator: enabled: true # Enable/disable OpenAPI decorator api_prefix: '/api' # API prefix for collection paths decoration_priority: 10 # Decorator priority (higher = runs first) label_property_candidates: # Property names to check for labels (in order) - name - title - label - displayName hydra_operations: enabled: true # Enable/disable Hydra operations subscriber api_prefix: '/api' # API prefix for operation paths event_priority: -10 # Event priority (negative = after API Platform)
Requirements
- PHP 8.2+
- ext-sodium (built into PHP 7.2+)
- Symfony 7.0+
- API Platform 3.0+
- Doctrine ORM 2.0+ / 3.0+
Architecture
Bundle Structure
api-platform-utils-bundle/
├── src/
│ ├── Schmunk42ApiPlatformUtilsBundle.php # Main bundle class
│ ├── DependencyInjection/
│ │ ├── Configuration.php # Configuration tree
│ │ └── Schmunk42ApiPlatformUtilsExtension.php # DI extension
│ ├── Service/
│ │ ├── UuidResolver.php # UUID resolver service
│ │ └── CredentialEncryption.php # Encryption service
│ ├── OpenApi/
│ │ └── RelationFieldSchemaDecorator.php # OpenAPI decorator
│ └── EventSubscriber/
│ └── AddHydraOperationsSubscriber.php # Event subscriber
├── config/
│ └── services.yaml # Service definitions
├── composer.json
├── README.md
└── CHANGELOG.md
How It Works
-
UuidResolver: Uses Doctrine metadata to detect UUID storage type (binary vs string), then performs partial matching via SQL LIKE queries
-
CredentialEncryption: Wraps PHP's libsodium crypto_secretbox functions for symmetric encryption with automatic nonce handling
-
RelationFieldSchemaDecorator: Decorates API Platform's SchemaFactory, processes INPUT schemas, detects Doctrine associations, and adds x-* extensions
-
AddHydraOperationsSubscriber: Listens to ResponseEvent, checks for JSON-LD item responses, extracts all operations from resource metadata, and enriches response
License
Proprietary - herzog kommunikation GmbH
Credits
Developed for the ZA7 (Zentrales Agentursystem Version 7) project.