HI everyone.
I have the following issue: there is Book entity, which must be available on two different endpoints. The first endpoint is a common route '/api/books' which would return all the books, and the second one is '/api/public/free-books' which would return only a subset of the books.
This is not a problem to set this up, it looks like this:
<?php
/**
* @ApiResource(
* itemOperations = {
* "get" = {"method" = "GET"}
* },
* collectionOperations = {
* "get" = {
* "method" = "GET"
* },
* "get_free" = {
* "method" = "GET",
* "path" = "/api/public/free-books"
* }
* }
* )
*/
class Book
The problem is that @id field of a collection is the same for both of the routes.
Is there a way to have different @id's.
Thanks!
There is no way, and there shouldnt be, imho.
Either you have one resource with 2 listings or you have 2 different resources with 1 listing each.
Since you cant map 1 entity to 2 resources, you need to have 2 entities (that maybe share a MappedSuperclass). Or you take the former approach, which is what you already have.
@backbone87 Why would I have 2 entities for _one_ entity? =)
Getting @id => /api/books when you call /api/public/free-books is weird.
We already have an option to create multiple collection get operations on a resource, returning wrong @id is simply a bug.
Why would I have 2 entities for one entity? =)
because the default implementations of basically all ApiPlatform interfaces can only handle these cases. you would have to customize pretty much every single component to allow one entity to map to more than one resource.
from an OO perspective: /api/public/free-books are still books, just like /api/books are. the fact that you can do something else with books that classify as "free-books" isnt a matter of model-design, but a matter of how you treat these models in services. and if free-books arent books, than they are 2 different entities.
@backbone87 I think you might get me wrong. Let me try to explain the problem in detail.
/api/public/free-books and /api/books both return the same entity (resource) collection of Books. It works totally fine with the current configuration except for one thing - the @id field is the same for both collections. _The problem is wrong @id field_.
and if free-books arent books, than they are 2 different entities.
there are not, those are one entity
you would have to customize pretty much every single component to allow one entity to map to more than one resource.
I am a bit familiar with API-Platform code and know it. I consider this to be a design flaw. Hydra is not limited to 4 operation (create,delete,update,read), the specification says we can have as many operations as we need to
there are not, those are one entity
There you have your answer. To one entity correspond one IRI (Internationalized Resource Identifier see Json-ld spec). Therefore, no matter what "route" you get the "Book" from it'll always be identified as "/api/book/1".
i got it, i think. he refers to the iri of the collection itself, not the iri of the items in the collection.
this should be a bug than probably
funily enough, i spotted the exact same problem indirectly in my current project :/
The IriConverter just takes the first GET route it finds and uses this to generate the collection IRI. So if you have multiple collection GET operations, you will always get the same IRI for both endpoints.
@backbone87 would matching the IRI to the requested url be a proper fix?
It would fix the usage of the IriConverter in this context, but not in general. Imho the IriConverter interface is not powerful enough to solve this in general.
@soyuka that exactly would be a solution. But this would mean IriConverter needs to be Request aware
Mhh, actually it may be patched in the RouteNameResolver no? It's the one responsible for getting a route name for a given resourceClass.
When I implemented subresources I added the context as a third argument to the getRouteName method, maybe we could use that to get the correct route name for this particular issue.
should work
This seems unresolved? The @id of all collectionOperations are the same. Currently the @id property depends on the ResourceClass only, not on the operation or the current request.
Another consequence is that an Iri can only be generated if the standard get collectionOperation is defined.