Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 543
Maramal Avatar asked Jul 24 '20 17:07

Maramal


People also ask

Why do you need an API integration platform?

With an API integration platform, departments are able to easily connect the best apps and tools available. This way, they can replace all-encompassing, yet inadequate options with a sleek and highly effective stack. 3. You need to quickly and easily create new APIs. Until recently, if you needed an API, you had two main options.

How to generate the IRI of an item in API platform?

By default, API Platform uses the first GET operation defined in itemOperations to generate the IRI of an item and the first GET operation defined in collectionOperations to generate the IRI of a collection. If you create a custom operation, you will probably want to properly document it.

What is an operation in API platform?

From an implementation point of view, an operation is a link between a resource, a route and its related controller. API Platform automatically registers typical CRUD operations and describes them in the exposed documentation (Hydra and Swagger).

Are Apis a necessity of modern enterprise it?

Today, APIs are a necessity of modern enterprise IT. It is less a matter of if APIs are needed, but rather how many are necessary and how they will be created and published. There are now at least 23,500 APIs in existence, and this may end up being only the tip of the proverbial iceberg.


1 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'
like image 82
yivi Avatar answered Sep 24 '22 12:09

yivi