PUT operation creates new embedded document instead of updating it on Api Platform

随声附和 提交于 2021-01-28 06:37:23

问题


I am stuck on an issue I cannot solve for few days now. As said in the title, Api Platform PUT operation based on annotations doesn't work as expected with regards to partial update on embedded document with MongoDB ODM.

Indeed, despite all the different configurations I tried, I didn't succeed in updating an embedded document already set in a parent document.

I tried to change annotations in relevant documents, for example by changing normalization and denormalization groups, by trying different embedded document strategies, by setting specific itemOperations for PUT method, etc. Documentation is quite poor on this specific issue because it seems mainly made for SQL operations using Doctrine ORM.

The most "interesting" information I found comes from this chapter in Api Platform documentation : https://api-platform.com/docs/core/serialization/#denormalization

As it is written "If an @id key is present in the embedded resource, then the object corresponding to the given URI will be retrieved through the data provider. Any changes in the embedded relation will also be applied to that object.", corresponding document should be retrieved, but it doesn't.

I have a parent document, Page, with an embedded document, Basic, in an embedOne relationship.

/**
 * @ApiFilter(SearchFilter::class, properties={"basic.name": "ipartial", "basic.title": "exact"})
 * 
 * @ApiResource(
 *  normalizationContext={"groups"={"read"}},
 *  denormalizationContext={"groups"={"write"}}
 * )
 *
 * @ODM\Document
 */
class Page
{
    /**
     * @ODM\Id(strategy="increment", type="integer")
     */
    private $id;

    /**
     * Embedded document with data shared by all Pages and Modules such as name, title, etc.
     * 
     * @Assert\Valid
     * @Groups({"read", "write"})
     * @ODM\EmbedOne(targetDocument=Basic::class, strategy="set")
     */
    private $basic;
}

On the other side, I have Basic embedded document :

/**
 * @ApiResource()
 * 
 * @ODM\EmbeddedDocument
 */
class Basic
{
    /**
     * @ApiProperty(identifier=true)
     * @Groups({"read", "write"})
     * @ODM\Id(strategy="INCREMENT", type="integer")
     */
    public $id;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $title;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $name;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $category;
}

So when I make a "POST" request on /api/pages such as this one:

{
    "basic": {
        "title": "Master",
        "name": "Peter Jackson",
        "category": "Director"
    }
}

I receive this 201 response:

{
    "@context": "\/api\/contexts\/Page",
    "@id": "\/api\/pages\/11",
    "@type": "Page",
    "basic": {
        "@id": "\/api\/basics\/21",
        "@type": "Basic",
        "id": 21,
        "title": "Master",
        "name": "Peter Jackson",
        "category": "Director"
    }
}

But I make a "PUT" request on this resource through api/pages/11 with those parameters:

{
  "basic": {
    "title": "Master",
    "name": "Steven Spielberg",
    "category": "Director"
  }
}

I receive this 200 response:

{
    "@context": "\/api\/contexts\/Page",
    "@id": "\/api\/pages\/11",
    "@type": "Page",
    "basic": {
        "@id": "\/api\/basics\/22",
        "@type": "Basic",
        "id": 22,
        "title": "Master",
        "name": "Steven Spielberg",
        "category": "Director"
    }
}

As you can see a new Basic embedded document is generated for the PUT operation in which the values set in the request are used. But I don't want this to happen, I want to systematically update the embedded document created, since it has been created. Thanks a lot if you know how to deal with this. Cheers!


回答1:


I think this is your problem. You need to set the id on embedded Relations otherwise they will be created.

{
  "basic": {
    "@id": "\/api\/basics\/21",
    "title": "Master",
    "name": "Steven Spielberg",
    "category": "Director"
  }
}

From the docs:

If an @id key is present in the embedded resource, then the object corresponding to the given URI will be retrieved through the data provider. Any changes in the embedded relation will also be applied to that object.

If no @id key exists, a new object will be created containing data provided in the embedded JSON document.


来源:https://stackoverflow.com/questions/57345434/put-operation-creates-new-embedded-document-instead-of-updating-it-on-api-platfo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!