api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.45k stars 875 forks source link

Field incorrectly shows up as hydra @context but is not included in @vocab #2782

Open weaverryan opened 5 years ago

weaverryan commented 5 years ago

Hi!

Apologies if I'm misunderstanding something :); Suppose you have this situation:

/**
 * @ApiResource(
 *     normalizationContext={"groups"={"cheese_listing:read"}},
 *     denormalizationContext={"groups"={"cheese_listing:write"}
 * )
 * @ORM\Entity()
 */
class CheeseListing
{
    // ...

    private $isPublished;

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

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

This has an isPublished field, which is not included in the normalization or denormalization context. This field is simply not part of the API in any way. However, if you go to: https://localhost:8000/api/contexts/cheese_listings, it is present:

{
  "@context": {
    "@vocab": "https://localhost:8000/api/docs.jsonld#",
    "hydra": "http://www.w3.org/ns/hydra/core#",
    "isPublished": "cheese_listings/isPublished"
  }
}

I believe the isPublished field should not be there. And, to further my point, if you go to https://localhost:8000/api/docs.jsonld to look at the vocab, there is no hydra:property for cheese_listings/isPublished. In other words, the isPublished property in the hydra @context is referring to a property that doesn't exist anywhere.

Note: If I'm correct that the isPublished property should not be added to the cheese_listings context, things get more interesting if you add a filter referencing the field:

* @ApiFilter(BooleanFilter::class, properties={"isPublished"})

What should happen here? This adds a hydra:search to the collection resource like this:

 "hydra:search": {
    "@type": "hydra:IriTemplate",
    "hydra:template": "/api/cheeses{?isPublished}",
    "hydra:variableRepresentation": "BasicRepresentation",
    "hydra:mapping": [
      {
        "@type": "IriTemplateMapping",
        "variable": "isPublished",
        "property": "isPublished",
        "required": false
      }
    ]
  }

Should the presence of this filter now cause the property to be defined in https://localhost:8000/api/docs.jsonld - because it's referenced under the hydra:mapping?

Thanks!

soyuka commented 5 years ago

Hi, I merged a fix today that may be related: https://github.com/api-platform/core/pull/2788. Indeed, this field should not be present in the documentation and we probably pick the fields naively from the class properties without any additional checks. I'd say that this is a bug.

* @ApiFilter(BooleanFilter::class, properties={"isPublished"})

Mhh, but if this property isn't exposed to the API I'm not sure that we should be able to filter on it, indeed to me the property should now be defined in the documentation. Not sure :sweat_smile:

kriswillis commented 2 years ago

I'm experiencing the same thing and found that as a work-around you can annotate the property with #[Ignore] to prevent it from appearing in the context endpoint.