api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.45k stars 874 forks source link

Custom input dto: ID field disappears #5917

Closed codedge closed 9 months ago

codedge commented 1 year ago

API Platform version(s) affected: 3.2.1

Description
When using a custom input dto, that contains an id field, this field is not reflected in the generated GraphQL API schema. The other field, someIds, is properly reflected inside the docs.

How to reproduce

Entity

use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GraphQl;

#[
  ORM\Entity,
  ApiResource(
    mercure: false,
    graphQlOperations: [
            new GraphQl\Query(),
            new GraphQl\QueryCollection(paginationType: 'page'),
            new GraphQl\Mutation(
                resolver: MyCustomResolver::class,
                input: MyCustomDto::class,
                name: 'assignImagesTo',
            ),
    ]
  )
]
class MyEntity
{

}

MyCustomDto

final class MyCustomDto
{
    #[
        Assert\NotBlank,
        Assert\Uuid,
    ]
    public string $id;

    /**
     * @var array<string>
     */
    public array $someIds = [];

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

    public function setId(string $id): MyCustomDto
    {
        $this->id = $id;

        return $this;
    }

    public function getSomeIds(): array
    {
        return $this->someIds;
    }

    public function getSomeIds(array $ids): MyCustomDto
    {
        $this->someIds = $ids;

        return $this;
    }
}

Instead, the field _id needs to be given as input which is then hydrated into the DTOs field id. See the difference with underscore _.

2023-10-23_093438

Possible Solution

Additional Context

I am unsure if this is a bug or some magic. I could live with this change if this would be explained somewhere. To my knowledge this worked differently before and we could pass _id and/or id as fields to a mutation with custom dto.

soyuka commented 1 year ago

Mhh looks like a bug but not sure from where it comes (maybe related to https://github.com/api-platform/core/issues/5914 ?). Also you should avoid using input for that can't you declare the Mutation directly on the DTO?

codedge commented 1 year ago

declare the Mutation directly on the DTO

Can you eleborate on that? I don't understand how I should define it diffently to the input and resolver inside the entity.

soyuka commented 1 year ago
#[GraphQl\Mutation(
    resolver: MyCustomResolver::class,
)]
class MyDto {}

I wonder why the id field changes though...

codedge commented 1 year ago

@soyuka I found the place where the id field disappears. In FieldsBuilder.php the id from the input DTO is rewritten to _id

// guess union/intersect types: check each type until finding a valid one
foreach ($propertyTypes as $propertyType) {
    if ($fieldConfiguration = $this->getResourceFieldConfiguration($property, $propertyMetadata->getDescription(), $propertyMetadata->getDeprecationReason(), $propertyType, $resourceClass, $input, $operation, $depth, null !== $propertyMetadata->getSecurity())) {
        $fields['id' === $property ? '_id' : $this->normalizePropertyName($property, $resourceClass)] = $fieldConfiguration;
        // stop at the first valid type
        break;
    }
}

which was introduced with the 3.2.0 release.

I think, I get the intention behind and it works in all my cases. I just did not see anything about this logic in the docs somethere.

NicoHaase commented 11 months ago

Do you have any additional ideas about this problem? I'm facing the same errors after updating from v3.1.x to v3.2.x

stale[bot] commented 9 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.