Why do I get "No item route associated with the type" when using Api-Platform?

Viewed 8509

My project is built in Symfony 5 and API-Platform to consume it from a JS client. In this scenario, I have a Question entity related to an Answer entity (One-to-many respectively).

Whenever I try to call /api/questions or /api/answers I get this error: "No item route associated with the type "App\Entity\Answer":

In order to API resources this is what I have configured with maker bundle:

- App\Entity\Question:

/**
 * @ORM\Entity(repositoryClass=QuestionRepository::class)
 * @ApiResource
 * @ApiFilter(SearchFilter::class, properties={"status": "exact"})
 */
class Question
{
    // ...
    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="questions")
     * @ORM\JoinColumn(nullable=false)
     */
    private $owner;

    // ... 

    /**
     * @ORM\OneToMany(targetEntity=Answer::class, mappedBy="question", orphanRemoval=true)
     */
    private $answers;

    // ...

    /**
     * @return Collection|Answer[]
     */
    public function getAnswers(): Collection
    {
        return $this->answers;
    }

    public function addAnswer(Answer $answer): self
    {
        if (!$this->answers->contains($answer)) {
            $this->answers[] = $answer;
            $answer->setQuestion($this);
        }

        return $this;
    }

    public function removeAnswer(Answer $answer): self
    {
        if ($this->answers->contains($answer)) {
            $this->answers->removeElement($answer);
            // set the owning side to null (unless already changed)
            if ($answer->getQuestion() === $this) {
                $answer->setQuestion(null);
            }
        }

        return $this;
    }

    // ...
}

- App\Entity\Answer:

/**
 * @ORM\Entity(repositoryClass=AnswerRepository::class)
 * @ApiResource
 */
class Answer
{
    // ...
    
    /**
     * @ORM\ManyToOne(targetEntity=Question::class, inversedBy="answers")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotBlank
     */
    private $question;

    // ...

    public function getQuestion(): ?Question
    {
        return $this->question;
    }

    public function setQuestion(?Question $question): self
    {
        $this->question = $question;

        return $this;
    }
   
    // ...
}

Not sure if this is relevant to this issue: I configured config/api_platform/resources.yaml on api_platform.yaml:

App\Entity\Answer:
  attributes:
    security: 'is_granted("ROLE_USER")'
    security_message: 'Only the authenticated user can see answers'
  collectionOperations:
    get:
      security: 'is_granted("ROLE_USER")'
      security_message: 'Only the authenticated user can get answers'
    post:
      security: 'is_granted("ROLE_USER")'
      security_message: 'Only the authenticated user can save answers'
  itemOperations:
      put:
        security: 'is_granted("ROLE_ADMIN") or object.owner == user'
        security_message: 'Only the authenticated user or administrators can update answers'
      delete:
        security: 'is_granted("ROLE_ADMIN")'
        security_message: 'Only administrators can delete answers'

App\Entity\Question:
  attributes:
    security: 'is_granted("ROLE_USER")'
    security_message: 'Only the authenticated user can see questions'
  collectionOperations:
    get:
      security: 'is_granted("ROLE_ADMIN")'
      security_message: 'Only the authenticated user or administrators can get questions'
    post:
      security: 'is_granted("ROLE_USER")'
      security_message: 'Only the authenticated user can save questions'
  itemOperations:
      get:
        security: 'is_granted("ROLE_ADMIN") or object.owner == user'
        security_message: 'Only the authenticated user or administrators can get questions'
      put:
        security: 'is_granted("ROLE_ADMIN") or object.owner == user'
        security_message: 'Only the authenticated user or administrators can update questions'
      delete:
        security: 'is_granted("ROLE_ADMIN")'
        security_message: 'Only administrators can delete questions'

The Swagger UI displays information about Question and Answer entity resources:

And this is what debug:route displays regarding Answer:

  api_answers_get_collection                      GET        ANY      ANY    /api/answers.{_format}
  api_answers_post_collection                     POST       ANY      ANY    /api/answers.{_format}
  api_answers_put_item                            PUT        ANY      ANY    /api/answers/{id}.{_format}
  api_answers_delete_item                         DELETE     ANY      ANY    /api/answers/{id}.{_format}

What is wrong here?

2 Answers

TLDR:

For all resources, you need to have the basic **item ** GET /resource/{id} route.



The error message is very explicit:

No item route associated with the type "App\Entity\Answer"

If you check your resource definition for Answer you will see:

itemOperations:
      put:
        security: 'is_granted("ROLE_ADMIN") or object.owner == user'
        security_message: 'Only the authenticated user or administrators can update answers'
      delete:
        security: 'is_granted("ROLE_ADMIN")'
        security_message: 'Only administrators can delete answers'

So you basically only have delete and update routes, but do not have a basic item retrieve route (GET /api/answers/123). By defining the routes explicitly, whatever route you do not define you disable.

That is confirmed with the output from the API docs: enter image description here

Without that, it is impossible to get a valid IRI for the resource. Without a valid GET route for a resource the system cannot generate a URL for each resource item, and since those URLs/IRIs are used as identifiers by the system, these should always be defined.

You just need to add the configuration for the item route back:

itemOperations:
      put:
        security: 'is_granted("ROLE_ADMIN") or object.owner == user'
        security_message: 'Only the authenticated user or administrators can update answers'
      delete:
        security: 'is_granted("ROLE_ADMIN")'
        security_message: 'Only administrators can delete answers'
      get:
        security: 'is_granted("ROLE_USER")'
        security_message: 'Only the authenticated user can get answers'

This can be caused also when you have an Entity with the same name but that other one doesn't have an @ApiResource setup.

Like Answer in src/Entity/Answer and Answer in src/Entity/Questions/Answer

Related