api-platform icon indicating copy to clipboard operation
api-platform copied to clipboard

Graphql Input DTO does not respect serialization groups

Open BernardA opened this issue 3 years ago • 0 comments

API Platform version(s) affected: 2.6.8

Description
Converting an User entity from graphql only to both REST/graphql. Created an input DTO to replace a WriteStage code that hashed the password and created email confirmation token.

All properties that are set to public on the input DTO will show on the createUserInput, regardless of the serialization group.

It seems to respect the serialization groups for REST ( see bottom).

How to reproduce

App\Entity\User

   .....
  graphql:[
    'item_query' => ['normalization_context' => ['groups' => ['get-admin']]],
    'collection_query' => [
        'security' => "is_granted('ROLE_ADMIN')",
        'normalization_context' => ['groups' => ['get-admin']]
    ],
    'update' => [
        'security' => "is_granted('ROLE_USER') and object.owner == user is_granted('ROLE_ADMIN')",
        'denormalization_context' => ['groups' => ['put-profile-change', 'put']],
        'validation_groups' => ['put-profile-change', 'put']
    ],
    'create' => [
        'denormalization_context' => ['groups' => ['post']],
        'validation_groups' => ['post']
    ]
],

 .....

#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
#[Groups(["get", "get-admin", "get-owner"])]
public int $id;

#[ORM\Column(type: 'string', length:180)]
#[Groups(["post", "post-social-register-google", "put", "put-profile-change", "get-owner", "get-admin"])]
private string $email;

 #[ORM\Column(type: 'string', length:180, unique:true)]
 #[Groups(["post", "post-social-register-google", "get", "get-admin", "get-owner", "put-register-social"])]
private string $username;

#[ORM\Column(type:'string', length:180)]
#[Groups(["post"])]
private string $password;

#[Groups(["post"])]
private string $passwordConfirmation;

 #[ORM\Column(type:'json')]
 #[Groups(["get-admin", "get-owner"])]
private array $roles = [];

 #[ORM\Column(type: 'datetime_immutable')]
 #[Groups(["get-admin", "get-owner"])]
private \DateTimeImmutable $createdAt;

#[ORM\Column(type: 'datetime_immutable', nullable:true)]
#[Groups(["get-admin"])]
private \DateTimeImmutable $passwordChangedAt;

#[ORM\Column(type: 'boolean')]
#[Groups(["get-admin"])]
private bool $isEnabled;

#[ORM\Column(type:'string', length:40, nullable:true)]
private string|null $confirmationToken;

 ........

On App\Dto\UserInput

  class UserInput
{
/**
 * @var string
 */
#[Groups(["post", "post-social-register-google", "put", "put-profile-change", "get-owner", "get-admin"])]
#[Assert\NotBlank(groups:["post", "post-social-register-google"])]
#[Assert\Email(groups:["post", "post-social-register-google"])]
public string $email;

/**
 * @var string
 */
#[Groups(["post", "post-social-register-google", "get", "get-admin", "get-owner", "put-register-social"])]
#[Assert\NotBlank(groups:["post"])]
#[Assert\Length(min:10, max:50, groups:["post", "post-social-register-google", "put-register-social"])]
public string $username;

/**
 * @var string $password
 * The hashed password
 */
#[Groups(["post"])]
#[Assert\NotBlank(groups:["post"])]
#[Assert\Regex(
    pattern:"/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{10,50}$)/",
    groups:["post"]
)]
public string $password;

/**
 * @var string
 * 
 */
#[Groups(["post"])]
public string $passwordConfirmation;

#[Groups(["get-admin", "get-owner"])]
public array $roles = [];

 /**
 * @var \DateTimeImmutable $createdAt
 *
 */
#[Groups(["get-admin", "get-owner"])]
public \DateTimeImmutable $createdAt;

/**
 * @var \DateTimeImmutable $passwordChangedAt
 *
 */
#[Groups(["get-admin"])]
private \DateTimeImmutable $passwordChangedAt;

/**
 * @var bool $isEnabled
 *
 */
#[Groups(["get-admin"])]
public bool $isEnabled;

So, the intended input to create user is:

    email
    username
    password
    paswordConfirmation

The createUserInput will look like this for above:

Screenshot 2022-05-14 at 10 27 57

While for REST:

 #[ApiResource(
   collectionOperations: [
    'post' => [
        'denormalization_context' => [
            'groups' => ["post"],
            'validation_groups' => ["post"] 
        ]
    ]
],

Input will be as intended: Screenshot 2022-05-14 at 10 28 35

Possible Solution

Additional Context

BernardA avatar May 14 '22 08:05 BernardA