I’m trying to define an entity with multiple endpoints using Api Platform. When I try to define multiple Get or GetCollection endpointd, it returns a 404 error. Looking for the reason, the only conclusion I can find was a bad uriTemplate definition, but does not make sense to me.
I try the next and it work, but I don’t understand why.
If I define the endpoint like /sport_centers_top_rated it works
If I define the endpoint like /sport_centers/top_rated it does not work.
I can don’t understand why.
Here is my class definition:
<?php
namespace AppEntityApp;
use ApiPlatformMetadataApiResource;
use ApiPlatformMetadataDelete;
use ApiPlatformMetadataGet;
use ApiPlatformMetadataGetCollection;
use ApiPlatformMetadataPost;
use ApiPlatformMetadataPut;
use AppControllerAppSportCenterSportCenterCreateController;
use AppControllerAppSportCenterSportCenterDeleteController;
use AppControllerAppSportCenterSportCenterReadController;
use AppControllerAppSportCenterSportCenterUpdateController;
use AppEntityMasterCity;
use AppRepositoryAppSportCenterRepository;
use AppTraitsEntityDatetimeTrait;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
use SymfonyComponentSerializerAttributeGroups;
#[ORMTable(schema: 'app')]
#[ORMEntity(repositoryClass: SportCenterRepository::class)]
#[ORMHasLifecycleCallbacks]
#[ApiResource(
operations: [
new Get(
name: 'sport_center:read'
),
new Get(
uriTemplate: '/sport_centers/{id}/sports',
controller: SportCenterReadController::class,
name: 'sport_center:read:sport_types'
),
new Get(
uriTemplate: '/sport_centers/{id}/reserves_availability',
controller: SportCenterReadController::class,
name: 'sport_center:read:reserves_availability'
),
new GetCollection(
uriTemplate: '/sport_centers',
controller: SportCenterReadController::class,
name: 'sport_center:read:list'
),
new GetCollection(
uriTemplate: '/sport_centers/top_reserves',
controller: SportCenterReadController::class,
normalizationContext: [
'groups' => [
'sport_center:read:top_rated'
]
],
name: 'sport_center:read:list:top_reserves'
),
new Post(
uriTemplate: '/sport_centers',
controller: SportCenterCreateController::class,
name: 'sport_center:write:create'
),
new Put(
uriTemplate: '/sport_centers/{id}',
controller: SportCenterUpdateController::class,
denormalizationContext: [
'groups' => [
'sport_center:write:update',
]
],
name: 'sport_center:write:update'
),
new Delete(
uriTemplate: '/sport_centers/{id}',
controller: SportCenterDeleteController::class,
name: 'sport_center:write:delete'
),
],
normalizationContext: [
'groups' => [
'sport_center:read',
]
],
denormalizationContext: [
'groups' => [
'sport_center:write',
]
]
)]
class SportCenter
{
use DatetimeTrait;
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
#[Groups(
groups: [
'sport_center:read',
'court:write',
'court:read',
'reserve:read',
'reserve:read:search_reserves',
'city:read'
]
)]
private int $id;
#[ORMColumn(length: 255)]
#[Groups(
groups: [
'sport_center:write',
'sport_center:read',
'court:read',
'sport_center:write:update',
'reserve:read',
'reserve:read:search_reserves',
'city:read'
]
)]
private string $name;
#[ORMColumn(length: 255)]
#[Groups(
groups: [
'sport_center:write',
'sport_center:read',
'court:read',
'reserve:read',
'sport_center:write:update',
'city:read'
]
)]
private string $street;
#[ORMColumn(length: 255)]
#[Groups(
groups: [
'sport_center:write',
'sport_center:read',
'court:read',
'sport_center:write:update',
]
)]
private string $postalCode;
#[ORMOneToMany(mappedBy: 'sportCenter', targetEntity: Court::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[Groups(
groups: [
'sport_center:read',
'sport_center:read:details:admin'
]
)]
private Collection $courts;
#[ORMManyToOne(inversedBy: 'sportCenters')]
#[ORMJoinColumn(nullable: false)]
private User $admin;
#[ORMManyToOne(inversedBy: 'sportCenters')]
#[Groups(
groups: [
'sport_center:write',
'sport_center:read',
'court:read',
'sport_center:write:update',
'reserve:read',
'reserve:read:search_reserves'
]
)]
private City $city;
public function __construct()
{
$this->courts = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getStreet(): ?string
{
return $this->street;
}
public function setStreet(string $street): self
{
$this->street = $street;
return $this;
}
public function getPostalCode(): ?string
{
return $this->postalCode;
}
public function setPostalCode(string $postalCode): self
{
$this->postalCode = $postalCode;
return $this;
}
/**
* @return Collection<int, Court>
*/
public function getCourts(): Collection
{
return $this->courts;
}
public function addCourt(Court $court): self
{
if (!$this->courts->contains($court)) {
$this->courts->add($court);
$court->setSportCenter($this);
}
return $this;
}
public function removeCourt(Court $court): self
{
if ($this->courts->removeElement($court)) {
// set the owning side to null (unless already changed)
if ($court->getSportCenter() === $this) {
$court->setSportCenter(null);
}
}
return $this;
}
public function getAdmin(): ?User
{
return $this->admin;
}
public function setAdmin(?User $admin): self
{
$this->admin = $admin;
return $this;
}
public function getCity(): ?City
{
return $this->city;
}
public function setCity(?City $city): static
{
$this->city = $city;
return $this;
}
public function getSportTypes(): array
{
$sports = [];
foreach ($this->courts as $court) {
$sports[] = $court->getSport()->value;
}
return array_unique($sports);
}
#[Groups([
'sport_center:read'
])]
public function getNCourts()
{
return sizeof($this->getCourts());
}
}
Sulex95 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.