Skip to content

Handle PATCH with ObjectMapper #7693

@Cafeine42

Description

@Cafeine42

Description
When using Symfony ObjectMapper in a PATCH operation, properties that are not sent in the request payload appear to be overwritten (set to null) instead of being left unchanged. This makes it difficult to use ObjectMapper for partial updates.

Problem
ObjectMapper does not seem to distinguish between:

  • a property that is explicitly provided as null in the input DTO, and
  • a property that is not initialized / not provided at all in the PATCH payload.

As a result, non-sent properties are not ignored during mapping and may unintentionally nullify existing entity values.

Requested Documentation or Feature
It would be helpful to clarify or support a recommended way to use ObjectMapper to implement an API PATCH operation, for example:

  • an option or pattern to ignore non-initialized DTO properties during mapping, or
  • clear guidance on whether input DTO properties are expected to be nullable for PATCH, and how partial updates should be handled safely.

A concrete example of a PATCH operation using ObjectMapper (DTO → existing entity) that demonstrates proper partial update behavior would greatly help.

See Cafeine42/api-platform-sandbox@27ee5f1 for reproducer.

Additional Context / Current Workaround

I implemented a custom condition:

class IsNotNullCondition implements ConditionCallableInterface
{
    public function __invoke(mixed $value, object $source, ?object $target): bool
    {
        return null !== $value;
    }
}

and used it with:

#[Map(if: IsNotNullCondition::class)]

to prevent ObjectMapper from overwriting properties when they are not provided.

Limitation of This Approach

This workaround has a major drawback:
it completely prevents using PATCH to explicitly set a property to null.

To make this work, it requires:

  • setting null as the default value for all DTO properties, and
  • adapting validation constraints to ignore null values everywhere.

This makes PATCH handling significantly more complex and error-prone, and it blurs the semantic difference between:

  • “field not provided”
  • “field explicitly set to null”.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions