You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Specifying an Input or an Output data representation
4
4
5
5
For a given resource class, you may want to have a different representation of this class as input (write) or output (read).
6
6
To do so, a resource can take an input and/or an output class:
@@ -17,100 +17,126 @@ use App\Dto\BookOutput;
17
17
18
18
/**
19
19
* @ApiResource(
20
-
* inputClass=BookInput::class,
21
-
* outputClass=BookOutput::class
20
+
* input=BookInput::class,
21
+
* output=BookOutput::class
22
22
* )
23
23
*/
24
24
final class Book
25
25
{
26
26
}
27
27
```
28
28
29
-
The `input_class` attribute is used during [the deserialization process](serialization.md), when transforming the user provided data to a resource instance.
30
-
Similarly, the `output_class` attribute is used during the serialization process, this class represents how the `Book` resource will be represented in the `Response`.
29
+
The `input` attribute is used during [the deserialization process](serialization.md), when transforming the user provided data to a resource instance.
30
+
Similarly, the `output` attribute is used during [the serialization process](serialization.md), this class represents how the `Book` resource will be represented in the `Response`.
31
31
32
-
To create a `Book`, we `POST` a data structure corresponding to the `BookInput` class and get back in the response a data structure corresponding to the `BookOuput` class.
32
+
The `input` and `output` attributes are taken into account by all the documentation generators (GraphQL and OpenAPI, Hydra).
33
33
34
-
To persist the input object, a custom [data persister](data-persisters.md) handling `BookInput` instances must be written.
35
-
To retrieve an instance of the output class, a custom [data provider](data-providers.md) returning a `BookOutput` instance must be written.
34
+
To create a `Book`, we `POST` a data structure corresponding to the `BookInput` class and get back in the response a data structure corresponding to the `BookOuput` class:
36
35
37
-
The `input_class` and `output_class` attributes are taken into account by all the documentation generators (GraphQL and OpenAPI, Hydra).
36
+

38
37
39
-
## Disabling the Input or the Output
38
+
To simplify object transformations we have to implement a Data Transformer that will convert the input into a resource or a resource into an output.
40
39
41
-
Both the `input_class` and the `output_class` attributes can be set to `false`.
42
-
If `input_class` is `false`, the deserialization process will be skipped, and no data persisters will be called.
43
-
If `output_class` is `false`, the serialization process will be skipped, and no data providers will be called.
40
+
With the following `BookInput`:
44
41
45
-
## Creating a Service-Oriented endpoint
42
+
```php
43
+
<?php
44
+
// src/Dto/BookInput.php
46
45
47
-
Sometimes it's convenient to create [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call)-like endpoints.
48
-
For example, the application should be able to send an email when someone has lost his password.
46
+
namespace App\Dto;
49
47
50
-
So let's create a basic DTO for this request:
48
+
final class BookInput {
49
+
public $isbn;
50
+
}
51
+
```
52
+
53
+
We can transform the `BookInput` to a `Book` resource instance:
In this case, we disable all operations except `POST`. We also set the `output_class` attribute to `false` to hint API Platform that no data will be returned by this endpoint.
86
+
And register it:
87
+
88
+
```yaml
89
+
# api/config/services.yaml
90
+
services:
91
+
# ...
92
+
'App\DataTransformer\BookInputDataTransformer': ~
93
+
# Uncomment only if autoconfiguration is disabled
94
+
#tags: [ 'api_platform.data_transformer' ]
95
+
```
96
+
97
+
To manage the output, it's exactly the same process. For example with `BookOutput` being:
84
98
85
-
Then, thanks to [a custom data persister](data-persisters.md), it's possible to trigger some custom logic when the request is received.
99
+
```php
100
+
<?php
101
+
// src/Dto/BookOutput.php
102
+
103
+
namespace App\Dto;
104
+
105
+
final class BookOutput {
106
+
public $name;
107
+
}
108
+
```
86
109
87
-
Create the data persister:
110
+
We can transform the `Book` to a `BookOutput` object:
When performing an update (e.g. `PUT` operation), the resource to be updated is read by ApiPlatform before the deserialization phase. To do so, it uses a [data provider](data-providers.md) with the `:id` parameter given in the URL. The *body* of the request is the JSON object sent by the client, it is deserialized and is used to update the previously found resource.
158
+
159
+

160
+
161
+
Now, we will update our resource by using a different input representation.
162
+
163
+
With the following `BookInput`:
164
+
165
+
```
166
+
<?php
167
+
// src/Dto/BookInput.php
168
+
169
+
namespace App\Dto;
170
+
171
+
final class BookInput {
172
+
/**
173
+
* @var \App\Entity\Author
174
+
*/
175
+
public $author;
176
+
}
177
+
```
178
+
179
+
We will implement a `BookInputDataTransformer` that transforms the `BookInput` to our `Book` resource instance. In this case, the `Book` (`/books/1`) already exists, so we will just update it.
Both the `input` and the `output` attributes can be set to `false`.
225
+
If `input` is `false`, the deserialization process will be skipped, and no data persisters will be called.
226
+
If `output` is `false`, the serialization process will be skipped, and no data providers will be called.
227
+
228
+
## Input/Output metadata
229
+
230
+
When specified, `input` and `output` attributes support:
231
+
- a string representing the class to use
232
+
- a falsy boolean to disable them
233
+
- an array to specify more metadata for example `['class' => BookInput::class, 'name' => 'BookInput', 'iri' => '/book_input']`
234
+
235
+
236
+
## Using DTO objects inside resources
237
+
238
+
Because ApiPlatform can (de)normalize anything in the supported formats (`jsonld`, `jsonapi`, `hal`, etc.), you can use any object you want inside resources. For example, let's say that the `Book` has an `attribute` property that can't be represented by a resource, we can do the following:
239
+
240
+
```php
241
+
<?php
242
+
// api/src/Entity/Book.php
243
+
244
+
namespace App\Entity;
245
+
246
+
use ApiPlatform\Core\Annotation\ApiResource;
247
+
use App\Dto\Attribute;
248
+
249
+
/**
250
+
* @ApiResource(
251
+
* input=BookInput::class,
252
+
* output=BookOutput::class
253
+
* )
254
+
*/
255
+
final class Book
256
+
{
257
+
/**
258
+
* @var Attribute
259
+
**/
260
+
public $attribute;
261
+
262
+
public $isbn;
263
+
}
127
264
```
128
265
129
-
Instead of a custom data persister, you'll probably want to leverage [the Symfony Messenger Component integration](messenger.md).
266
+
The `Book``attribute` property will now be an instance of `Attribute` after the (de)normalization phase.
0 commit comments