Description
API Platform version(s) affected: 2.7(with new metadata), 3.0, 3.1/main
Description
Hello,
I am not sure if this is necessarily a bug, or a misunderstanding on the approach on my part.
While I was upgrading a large project from api-platform 2.6 >> 3.x, I am running into an interesting issue during serialization.
Example
Here is an example to explain the situation.
- Lets say I have an ApiResource
Car
.- Car has a referenced property
Wheel
. This can be a collection. ButWheel
is not an ApiResource.Wheel
has a referenced propertyTire
which is an ApiResource.
- Car has a referenced property
You can see in this situation, The nesting of entities to serialize is Resource object > non-Resource object > Resource object.
When you serialize Car
, its serialization context bubbles down all the way to Wheel
and to Tire
.
- When serializing
Car
$context['operation'] is set to Car. This is passed down toWheel
.- When serializing
Wheel
, $context['operation'] is still set to Car. But its not used in theAbstractObjectNormalizer
, so simply passed on- When serializing
Tire
, $context['operation'] is still set to Car.AbstractItemNormalizer
will look at the passed$context['operation']
and will not try to determine the correct operation forTire
. This is where the issue happens.
- When serializing
- When serializing
The biggest culprit ive run into is \ApiPlatform\Symfony\Routing\IriConverter::getIriFromResource()
uses the given $operation
parameter to generate an iri. But with the wrong context, it will throw an Exception saying Unable to generate an IRI for the item of type
Possible Solution
-
unset the
$context['operation']
each time we go into a new nested level (Perhaps at the $childContext level).
\ApiPlatform\Serializer\AbstractItemNormalizer::getAttributeValue
seems to generate the$context['operation']
whenever it needs one.
If going with this approach, unsetting the operation context towards the beginning of::getAttributeValue
seems to fix this issue, although I have not fully tested it. -
Make everything an ApiResource.
This is another way to solve this does not seem right. If I mark every nested property of an ApiResource class also as an ApiResource, I will not run into problems. But I would have to alter the generated Api docs for each class. I would also really be mis-using the ApiResource attribute for simple serialization purposes.
Bug vs Documentation
Of the two approaches above,
If the intention with 3.x is for every class needing to be marked as ApiResource
— This is not a bug. I think additional documentation to make it clearer would help.
If that is not the intention,
Than I will definitely start working on a clean PR for this.