Skip to content

[GraphQL] How to use DTOs? #1870

@IonBazan

Description

@IonBazan

Is it possible to use a DTO without registering it as ApiResource? I would like to expose a DTO from my Entity but it is not passed to SchemaBuilder unless I register it as ApiResource. This however requires to add an identifier to the DTO.
It works perfectly on JSON endpoints since coordinates are being serialized properly. This does not happen for GraphQL because API Platform does not know about the DTO at all and does not build schema for this.

Consider example entity:

<?php

namespace App\Entity;

use App\DTO\Coordinates;
use Ramsey\Uuid\UuidInterface;

class Country
{
    /** @var UuidInterface */
    protected $id;

    /** @var float|null */
    protected $latitude;

    /** @var float|null */
    protected $longitude;

    /** @var string */
    protected $name;

    public function getId(): UuidInterface
    {
        return $this->id;
    }

    public function getLatitude(): ?float
    {
        return $this->latitude;
    }

    public function setLatitude(?float $latitude): Country
    {
        $this->latitude = $latitude;

        return $this;
    }

    public function getLongitude(): ?float
    {
        return $this->longitude;
    }

    public function setLongitude(?float $longitude): Country
    {
        $this->longitude = $longitude;

        return $this;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): Country
    {
        $this->name = $name;

        return $this;
    }

    public function setCoordinates(Coordinates $coordinates): Country
    {
        return $this->setLatitude($coordinates->getLatitude())
            ->setLongitude($coordinates->getLongitude());
    }

    public function getCoordinates(): Coordinates
    {
        return new Coordinates($this->getLatitude(), $this->getLongitude());
    }

    public function __toString(): string
    {
        return $this->getName();
    }
}

and Coordinates DTO:

<?php

namespace App\DTO;

use ApiPlatform\Core\Annotation\ApiProperty;

class Coordinates
{
    /** @var float */
    protected $latitude;

    /** @var float */
    protected $longitude;

    public function __construct(float $latitude, float $longitude)
    {
        $this->latitude = $latitude;
        $this->longitude = $longitude;
    }

    public function getLatitude(): float
    {
        return $this->latitude;
    }

    public function setLatitude(float $latitude): Coordinates
    {
        $this->latitude = $latitude;

        return $this;
    }

    public function getLongitude(): float
    {
        return $this->longitude;
    }

    public function setLongitude(float $longitude): Coordinates
    {
        $this->longitude = $longitude;

        return $this;
    }

    /**
     * This is needed only to register it as Api Resource
     * @ApiProperty(identifier=true)
     */
    public function getId()
    {
        return md5($this->getLatitude().' '.$this->getLongitude());
    }
}

Hack to make Coordinates show in GraphQL endpoints:

resources:
    # [...]
    App\DTO\Coordinates:
        shortName: Coordinate
        attributes:
            normalization_context:
                groups: ['read']
        collectionOperations: {}
        itemOperations: {}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions