Adding metadata to an API Platform Input DTO
For API-based projects, we heavily rely on API Platform as the foundation. How can I attach some metadata to my input DTO? That was a task I wanted to solve recently.
The Input DTO in question was a read-only class with two properties set via constructor injection:
<?php
declare(strict_types=1);
namespace App\ApiResource;
use ApiPlatform\Metadata\ApiProperty;
final readonly class MyInput
{
public function __construct(
public string $firstName,
public string $lastName,
) {
}
Adding another property to the constructor would have exposed the property to the API client, which is something I wanted to avoid. The basic idea was that API Platform sets an additional property (e.g., a transaction reference) in the input class so that I can pass the instance to several other methods.
I could have introduced the property, including getter and setter methods, but that felt "odd" given that the existing properties were exposed as read-only properties.
I then experimented with overwriting some API Platform core classes and tweaking the Symfony Serializer component. Both approaches resulted in too much code for such a simple task, so I decided against it.
In the end, I settled on the most obvious solution: setting the property in the class constructor. Since I don't need some complicated logic to generate a transaction reference number, this felt like the best approach to solving the problem.
The resulting DTO class looks like this:
<?php
declare(strict_types=1);
namespace App\ApiResource;
use ApiPlatform\Metadata\ApiProperty;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\UuidV4;
final readonly class MyInput
{
#[ApiProperty(readable: false)]
public UuidV4 $transactionReference;
public function __construct(
public string $firstName,
public string $lastName,
) {
$this->transactionReference = Uuid::v4();
}
}
Thanks to the #[ApiProperty(readable: false)]
attribute, the $transactionReference
property is not exposed in the API docs. And thanks to Symfony's UID component, generating the $transactionReference
was a one-liner:
$this->transactionReference = Uuid::v4();
Once again, this is a perfect example to show that simple problems can be solved with simple solutions.