core: Unable to update an embedded collection relation with a PATCH operation

API Platform version(s) affected: 3.1.8

Description

I’m trying to update an embedded relation with a PATCH operation. Basically this use case but with a PATCH instead of a PUT. However my relation is deleted and recreated instead of updated.

How to reproduce

  1. Create a resource with a collection.
  2. Try to update an item of this collection with a PATCH operation.

Possible Solution

I tried to debug the issue. I think the issue happens because when the request reach this line, $data['@id'] contains the id of my relation but $context[self::OBJECT_TO_POPULATE] is set and contains the entire collection instead of just the item.

If I update this line with

$childContext = $this->createChildContext($context, $attribute, $format);
$childContext[self::OBJECT_TO_POPULATE] = null;
$values[$index] = $this->denormalizeRelation($attribute, $propertyMetadata, $className, $obj, $format, $childContext);

then the request behave as expected, but I’m really not sure that this is the right fix.

Please tell me if I can do anything to help fix the issue (or if I’m doing anything wrong).

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 4
  • Comments: 17 (15 by maintainers)

Most upvoted comments

Hello !

I’m facing the same issue using PATCH. I’m confused since partial updates with PUT seems already deprecated and the notice ask us to use PATCH to keep the same behaviour :

https://github.com/api-platform/core/blob/main/src/Metadata/Resource/Factory/DeprecationResourceMetadataCollectionFactory.php#L36

$this->triggerDeprecationOnce($operation, 'extraProperties["standard_put"]', 'In API Platform 4 PUT will always replace the data, use extraProperties["standard_put"] to "true" on every operation to avoid breaking PUT\'s behavior. Use PATCH to use the old behavior.');

It looks like it’s not the case yet ?

Yes I know (I was only answering @soyuka question), and because non-standard PUT are now deprecated I’m trying to migrate to PATCH operations (the recommended solution) but it behaves almost the same way as a standard PUT with collections, hence the original issue.

Indeed that’s actually a BC break that can’t be avoided IMO - PATCH or (standard) PUT on the resource shouldn’t try to do a partial update on members of the resource, which is a problem if you’re currently relying on non-standard PUT behaviour that does that.

The second query fails because the column name is non-nullable. It seems that API Platform tries to create a completly new store with its pets, instead of replacing the existing one. I can upload a repository with my code if it can help better understand the issue.

Well that’s exactly what a standard PUT is supposed to do : create or replace a resource entirely. Sending partial data for a standard PUT is incorrect and should trigger a validation error IMO…

Keep using PUT 😉. I don’t think that we will deprecate the partial updates with put right away and even if we do it you’ll be able to keep the behavior with a normalizer.

PATCH is doing partial updates and yes it reuses objects. But on collection it replaces the collection. There are other PATCH specifications that we could implement. For these use cases we also worked on #1645 but there are no perfect solutions.