Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ApiResource parameters denormalizationContext and normalizationContext doesn't affect #1892

Closed
kadirov opened this issue Apr 23, 2021 · 26 comments

Comments

@kadirov
Copy link

kadirov commented Apr 23, 2021

API Platform version(s) affected: 2.6.4
Everything ok when you downgrade to 2.6.3

Description
ApiResource parameters denormalizationContext and normalizationContext doesn't affect.

How to reproduce
In version 2.6.4 - swagger shows all fields and ignores denormalizationContext and normalizationContext
But In versions before that, for example 2.6.3 - everything is ok. Swagger shows considering denormalizationContext and normalizationContext goups

How swagger looks with ApiPlatform version 2.6.3
image

Same code with 2.6.4
image

Original file is there: https://github.com/kadirov/api-starter-kit/blob/master/src/Entity/User.php

#[ApiResource(
    collectionOperations: [
        'get'                => [
            'security'              => "is_granted('ROLE_ADMIN')",
            'normalization_context' => ['groups' => ['users:read']],
        ],
        'post'               => [
            'controller' => UserCreateAction::class,
        ],
        'aboutMe'            => [
            'controller'      => UserAboutMeAction::class,
            'method'          => 'get',
            'path'            => 'users/about_me',
            'openapi_context' => [
                'summary'    => 'Shows info about the authenticated user',
            ],
        ],
        'auth'               => [
            'controller'      => UserAuthAction::class,
            'method'          => 'post',
            'path'            => 'users/auth',
            'openapi_context' => ['summary' => 'Authorization'],
        ],
        'authByRefreshToken' => [
            'controller'      => UserAuthByRefreshTokenAction::class,
            'method'          => 'post',
            'path'            => 'users/auth/refreshToken',
            'openapi_context' => ['summary' => 'Authorization by refreshToken'],
            'input'           => RefreshTokenRequestDto::class,
        ],
        'isUniqueEmail'      => [
            'controller'              => UserIsUniqueEmailAction::class,
            'method'                  => 'post',
            'path'                    => 'users/is_unique_email',
            'openapi_context'         => ['summary' => 'Checks email for uniqueness'],
            'denormalization_context' => ['groups' => ['user:isUniqueEmail:write']],
        ],
    ],
    itemOperations: [
        'changePassword' => [
            'controller'              => UserChangePasswordAction::class,
            'method'                  => 'put',
            'path'                    => 'users/{id}/password',
            'security'                => "object == user || is_granted('ROLE_ADMIN')",
            'openapi_context'         => ['summary' => 'Changes password'],
            'denormalization_context' => ['groups' => ['user:changePassword:write']],
        ],
        'delete'         => [
            'controller' => DeleteAction::class,
            'security'   => "object == user || is_granted('ROLE_ADMIN')",
        ],
        'get'            => [
            'security' => "object == user || is_granted('ROLE_ADMIN')",
        ],
        'put'            => [
            'security'                => "object == user || is_granted('ROLE_ADMIN')",
            'denormalization_context' => ['groups' => ['user:put:write']],
        ],
    ],
    denormalizationContext: ['groups' => ['user:write']],
    normalizationContext: ['groups' => ['user:read', 'users:read']],
)]
#[ApiFilter(OrderFilter::class, properties: ['id', 'createdAt', 'updatedAt', 'email'])]
#[ApiFilter(SearchFilter::class, properties: ['id' => 'exact', 'email' => 'partial'])]
#[UniqueEntity('email', message: 'This email is already used')]

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
class User implements
    UserInterface,
    UpdatedAtSettableInterface,
    CreatedAtSettableInterface,
    IsDeletedSettableInterface
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    #[Groups(['users:read'])]
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    #[Assert\Email]
    #[Groups(['users:read', 'user:write', 'user:put:write', 'user:isUniqueEmail:write'])]
    private $email;

    /**
     * @ORM\Column(type="string", length=255)
     */
    #[Groups(['user:write', 'user:changePassword:write'])]
    private $password;

    /**
     * @ORM\Column(type="array")
     */
    #[Groups(['user:read'])]
    private $roles = [];

    /**
     * @ORM\Column(type="datetime")
     */
    #[Groups(['user:read'])]
    private $createdAt;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups({"user:read"})
     */
    #[Groups(['user:read'])]
    private $updatedAt;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isDeleted = false;

   // here getter and setter methods...
}

Possible Solution
Downgrade to 2.6.3

Additional Context
Symfony version 5.2.6
PHP version 8.0.3
OS: tested on windows 10, Fedora 33, docker with Debian 10

@rabraghib
Copy link

I have the same issus, but if you checked the respenses schemas
normalization_context's have been applied, Only denormalizationContext's that dont work

@papylhomme
Copy link

Same problem here, downgrading to 2.6.3 works

@lebadapetru
Copy link

I feel a bit relieved that i'm not the only one facing this issue. i've opened a bug here but i think it's the wrong place for it.

@papylhomme
Copy link

for what it's worth the controllers seem to be working just fine, the only real problem is the swagger UI displaying the wrong schema

@kadirov
Copy link
Author

kadirov commented Apr 29, 2021

for what it's worth the controllers seem to be working just fine, the only real problem is the swagger UI displaying the wrong schema

No, if you send for example password field which not showed in swagger then api-platfoem ignores it

@imsheng
Copy link

imsheng commented Apr 29, 2021

Same problem here

@aglou
Copy link

aglou commented Apr 29, 2021

just to follow!

@miguelBarreiro85
Copy link

same problem

@weaverryan
Copy link

Btw, if anyone wants to do some digging, since the problem occurs between 2.6.3 and 2.6.4, here is the diff: api-platform/core@v2.6.3...v2.6.4

From that diff, api-platform/core#4138 looks particularly interesting. If someone having this issue could try to "revert" that PR manually on their local copy... to see if it makes any difference, that might help things :).

Cheers!

@guilliamxavier
Copy link

Indeed, several issues popped up after api-platform/core#4138 (more precisely the commit "Improve openapi performances"), for which the latest fix is api-platform/core#4247

@raph35
Copy link

raph35 commented Jun 3, 2021

for what it's worth the controllers seem to be working just fine, the only real problem is the swagger UI displaying the wrong schema

No, if you send for example password field which not showed in swagger then api-platfoem ignores it

Swagger display the wrong schema in the method but the controller still follow the right schema that is created with normalizationContext and denormalizationContext
(It seems that Swagger UI only display the wrong schema but the controllers still working and filter the data that have been posted

@Renrhaf
Copy link
Contributor

Renrhaf commented Jun 7, 2021

Same issue here, everything still works fine in the backend but the Swagger/ReDoc is not using the denormalization context data to show the right parameters.

@rabraghib
Copy link

PS: v2.6.5 this is still not fixed

@guilliamxavier
Copy link

Then this might be related to api-platform/core#4248 (or not)

@kadirov
Copy link
Author

kadirov commented Jun 23, 2021

PS: v2.6.5 this is still not fixed

How they not see yet this bug?

@alanpoulain
Copy link
Member

I don't see the bug anymore in 2.6.5.
@kadirov if I take your example.

2.6.4
image

2.6.5
image

@botris
Copy link

botris commented Jun 23, 2021

@alanpoulain I can confirm that the different issues I had around this problem have been fixed in 2.6.5

@rabraghib
Copy link

rabraghib commented Jun 23, 2021

@alanpoulain I just setup new app but it hasn't been fixed 😕

Screenshot 2021-06-23 104837

Here is the entity code

// App\Entity\Test

// .....

**
 * @ORM\Entity(repositoryClass=TestRepository::class)
 */
#[ApiResource(
    collectionOperations: ['get','post'],
    itemOperations: [
        'patch' => [
            'denormalization_context' => ['groups' => ['write']]
        ]
    ],
    denormalizationContext: ['groups' => ['create']],
    normalizationContext: ['groups' => ['read']],
)]
class Test
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    #[Groups(['read'])]
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    #[Groups(['read','create','write'])]
    private $prop1;

    /**
     * @ORM\Column(type="string", length=255)
     */
    #[Groups(['create','write'])]
    private $prop2;

    /**
     * @ORM\Column(type="string", length=255)
     */
    #[Groups(['write'])]
    private $prop3;

    // ....
}

@alanpoulain
Copy link
Member

@rabraghib
image

Please make sure:

  • Your entity has getters for your private properties:
    public function getId(): int
    {
        return $this->id;
    }

    public function getProp1(): string
    {
        return $this->prop1;
    }

    public function getProp2(): string
    {
        return $this->prop2;
    }

    public function getProp3(): string
    {
        return $this->prop3;
    }
  • You are using the last version of api-platform/core:
    docker-compose exec php composer req api-platform/core:^2.6.5

@rabraghib
Copy link

@alanpoulain yes it has getter & setter and I am using latest symfony version and version 2.6.5 of api platform

@alanpoulain
Copy link
Member

Make sure you cache is cleared.
Something is wrong in your project, you can try it on a new project, you will see that the issue is gone.

@rabraghib
Copy link

that is a new project 😕
but if it has been fixed thanks I'll figure out where is the problem

@kadirov
Copy link
Author

kadirov commented Jun 23, 2021

I've tested. Problem solved in 2.6.5!
Thank to all !!!

@kadirov kadirov closed this as completed Jun 23, 2021
@rabraghib
Copy link

thanks @alanpoulain its fixed as you said 👍

@jeanatpi
Copy link

jeanatpi commented Aug 12, 2022

Still have an issue with this example on Symfony 6 and version 2.6.8.

textDescription field does not appears in Swagger documentation for write model.

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\CheeseListingRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;

#[ORM\Entity(repositoryClass: CheeseListingRepository::class)]
#[ApiResource(
    shortName: "cheeses",
    denormalizationContext: ['groups' => ['write']],
    normalizationContext: ['groups' => ['read']],
)]
class CheeseListing
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Groups(["read","write"])]
    private ?string $title = null;

    #[ORM\Column(type: Types::TEXT)]
    #[Groups(["read"])]
    private ?string $description = null;

    #[ORM\Column]
    #[Groups(["read","write"])]
    private ?int $price = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

    #[ORM\Column]
    private bool $isPublished = false;

    public function __construct()
    {
        $this->createdAt = new \DateTimeImmutable();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }


    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(string $description): self
    {
        $this->description = $description;
        return $this;
    }

    #[Groups("write")]
    public function setTextDescription(string $description): self
    {
        $this->description = nl2br($description);
        return $this;
    }

    public function getPrice(): ?int
    {
        return $this->price;
    }

    public function setPrice(int $price): self
    {
        $this->price = $price;

        return $this;
    }

    #[Groups("read")]
    public function getCreatedAt(): ?\DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function isIsPublished(): ?bool
    {
        return $this->isPublished;
    }


    public function setIsPublished(bool $isPublished): self
    {
        $this->isPublished = $isPublished;

        return $this;
    }
}

@VladyslavChernyshov
Copy link

Still have an issue with this example on Symfony 6 and version 2.6.8.

3.0 rc2 also

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests