Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions core/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,167 @@ AppBundle\Entity\Book:

</configurations>

## Subresources

Since ApiPlatform 2.1, you can declare subresources. A subresource is a collection or an item that belongs to another resource. The starting point of a subresource must be a relation on an existing resource.

For example, let's create two entities (Question, Answer) and set up a subresource so that `/question/42/answer` gives us the answer to the question 42:

```php

// src/AppBundle/Entity/Answer.php

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
* Answer.
*
* @ORM\Entity
* @ApiResource
*/
class Answer
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\Column
*/
public $content;

/**
* @ORM\OneToOne(targetEntity="Question", mappedBy="answer")
*/
public $question;

public function getId()
{
return $this->id;
}
}
```

```php
<?php

// src/AppBundle/Entity/Question.php

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ApiResource
*/
class Question
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\Column
*/
public $content;

/**
* @ORM\OneToOne(targetEntity="Answer", inversedBy="question")
* @ORM\JoinColumn(referencedColumnName="id", unique=true)
* @ApiSubresource
*/
public $answer;

public function getId()
{
return $this->id;
}
}
```

Note that all we had to do is to set up `@ApiSubresource` on the `Question::answer` relation. Because the `answer` is a to-one relation, we know that this subresource is an item. Therefore the response will look like this:

```json
{
"@context": "/contexts/Answer",
"@id": "/answers/42",
"@type": "Answer",
"id": 42,
"content": "Life, the Universe, and Everything",
"question": "/questions/42"
}
```

If you put the subresource on a relation that is to-many, you will retrieve a collection.

Last but not least, Subresources can be nested, such that `/questions/42/answer/comments` will get the collection of comments for the answer to question 42.

You may want custom groups on subresources. Because a subresource is nothing more than a collection operation, you can set `normalization_context` or `denormalization_context` on that operation. To do so, you need to override `collectionOperations`. Based on the above operation, because we retrieve an answer, we need to alter it's configuration:

<configurations>

```php
<?php

// src/AppBundle/Entity/Answer.php

use ApiPlatform\Core\Annotation\ApiResource;

/**
* @ApiResource(collectionOperations={"api_questions_answer_get_subresource"={"method"="GET", "normalization_context"="{"groups"={"foobar"}}"}})
*/
class Answer
{
// ...
}
```

```yaml
# src/AppBundle/Resources/config/api_resources/resources.yml

AppBundle\Entity\Answer:
collectionOperations:
api_questions_answer_get_subresource:
method: 'GET' # nothing more to add if we want to keep the default controller
normalization_context: {'groups': ['foobar']}
```

```xml
<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->

<?xml version="1.0" encoding="UTF-8" ?>
<resources xmlns="https://api-platform.com/schema/metadata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://api-platform.com/schema/metadata
https://api-platform.com/schema/metadata/metadata-2.0.xsd">
<resource class="AppBundle\Entity\Answer">
<collectionOperations>
<collectionOperation name="api_questions_answer_get_subresource">
<attribute name="method">GET</attribute>
<attribute name="normalization_context">
<attribute name="groups">
<group>foobar</group>
</attribute>
</attribute>
</collectionOperation>
</collectionOperations>
</resource>
</resources>
```

</configurations>

Note that the operation name, here `api_questions_answer_get_subresource`, is the important keyword. It'll be automatically set to `$resources_$subresource(s)_get_subresource`. To find the correct operation name you may use `bin/console debug:router`.

## Creating Custom Operations and Controllers

API Platform can leverage the Symfony routing system to register custom operation related to custom controllers. Such custom
Expand Down
3 changes: 2 additions & 1 deletion index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
4. [Operations](core/operations.md)
1. [Enabling and Disabling Operations](core/operations.md#enabling-and-disabling-operations)
2. [Configuring Operations](core/operations.md#configuring-operations)
3. [Creating Custom Operations and Controllers](core/operations.md#creating-custom-operations-and-controllers)
3. [Subresources](core/operations.md#subresources)
4. [Creating Custom Operations and Controllers](core/operations.md#creating-custom-operations-and-controllers)
5. [Filters](core/filters.md)
1. [Doctrine ORM Filters](core/filters.md#doctrine-orm-filters)
1. [Search Filter](core/filters.md#search-filter)
Expand Down