Skip to main content

Adding metadata to an API Platform Input DTO

This blog post might be outdated!
This blog post was published more than one year ago and might be outdated!
· 2 min read
Stephan Hochdörfer
Head of IT Business Operations

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.