Api Platform DTO is not comprehensible

4 weeks ago 33
ARTICLE AD BOX
version
symfony 7.4
symfony/object-mapper 7.4
api-platform/symfony 4.2
php 8.4

Describe the problem

So I've been reading about the new recommandation for API Platform which is to use and map DTO instead of writing API Platform ressources metadata directly through the Entity.

See also https://api-platform.com/docs/core/dto/

So I've been trying to implement this with no luck yet.

Illustrate the problem with my code

Here's my simple entity :

# src/Entity namespace App\Entity; #[ORM\Entity(repositoryClass: CompanyRepository::class)] #[ORM\Table(name: 'company')] class Company { use TimestampableEntity; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::BIGINT)] #[Groups(['read:company'])] private ?int $id = null; #[ORM\Column(type: Types::STRING, length: 255)] #[Groups(['read:company'])] private string $name = ''; ... }

Here's my input Resource :

# src/Domain/Company/ApiResource namespace App\Domain\Company\ApiResource; use ApiPlatform\Doctrine\Orm\State\Options; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Post; use App\Entity\Company; use Symfony\Component\ObjectMapper\Attribute\Map; use Symfony\Component\Validator\Constraints as Assert; #[ApiResource( operations: [ new Post( uriTemplate: '/company', /** @todo security: 'is_granted("ROLE_ADMIN")', */ normalizationContext: ['groups' => ['read:company']], output: CompanyCreateOutput::class, name: 'create_company', ), ], stateOptions: new Options(entityClass: Company::class), )] #[Map(target: Company::class)] class CompanyCreateInput { public string $name = ''; }

Now here's my output :

# src/Domain/Company/ApiResource namespace App\Domain\Company\ApiResource; use App\Entity\Company; use Symfony\Component\ObjectMapper\Attribute\Map; use Symfony\Component\Serializer\Attribute\Groups; #[Map(source: Company::class)] class CompanyCreateOutput { #[Groups(['read:company'])] public int $id; #[Groups(['read:company'])] public string $name; #[Groups(['read:company'])] #[Map(source: 'created_at')] public string $createdAt; }

But well now when I call the route such as

POST {{url}}/company { "name": "This is a test" }

I got the following response :

{ "@context": { "@vocab": "https://api.project.local/api/docs.jsonld#", "hydra": "http://www.w3.org/ns/hydra/core#", "name": "CompanyCreateInput/name" }, "@type": "CompanyCreateInput", "@id": "/api/.well-known/genid/28ed6cfb3faf268d111c" }

Which is to me absolutely insane response.

What I'm trying to get

I want that when I create a resource (with a POST) that it return the created resource such as :

{ "id": 12345, "name": This is a test", "created_at": "29/12/2025 00:00:00" }

What I've been trying

I've been reading how it's been proceed to normalize the object the standard way using the ItemNormalizer::normalize which do include the output argument but it does not use it... It look like an error to me...

I've been trying to create a custom provider CompanyCreateRepresentationProvider but I didn't know how to use it and it does not looked like to be actually used ...

Read Entire Article