Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Serialization Groups for Writing

Serialization Groups for Writing

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

denormalizationContext is the COUNTERPART to chapter 23 – it controls WHICH fields a POST/PUT/PATCH request accepts AT ALL.

Adding denormalizationContext

api/src/Entity/Project.php
#[ApiResource(
    normalizationContext: ['groups' => ['project:read']],
    denormalizationContext: ['groups' => ['project:write']]
)]
#[ORM\Entity(repositoryClass: ProjectRepository::class)]
class Project
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    #[Groups(['project:read'])]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Assert\NotBlank]
    #[Groups(['project:read', 'project:write'])]
    private string $name = '';

    #[ORM\Column(type: 'text', nullable: true)]
    #[Groups(['project:read', 'project:write'])]
    private ?string $description = null;

    #[ORM\Column]
    #[Groups(['project:read'])]
    private \DateTimeImmutable $createdAt;

    // ... rest unchanged
}

id and createdAt belong ONLY to project:read – they must NOT be settable by the client (the id is assigned by the database, createdAt in the constructor). name and description belong to BOTH groups: readable AND writable.

Testing the behavior

curl -k -X POST https://localhost/api/projects \
  -H 'Content-Type: application/json' \
  -d '{"name": "New Project", "id": 999, "createdAt": "1970-01-01T00:00:00+00:00"}'

id and createdAt in the request body get SILENTLY IGNORED – NO error, but also NO effect, since they're NOT included in project:write. The database still assigns its OWN id, the constructor still sets its OWN createdAt.

Why not just use a readonly property?

PHP's own readonly keyword would trigger a FATAL error on ANY write attempt – serialization groups, by contrast, simply IGNORE the value SILENTLY, which is the DESIRED, more tolerant behavior for an API field (a client that accidentally sends id should NOT crash).

Tipp: project:write can be FURTHER split into project:create and project:update, in case creating and editing should differ in their allowed fields – for OUR project, the simpler shared group is currently enough.