# Using Data Transfer Objects (DTOs)
As stated in [the general design considerations](design.md), in most cases [the DTO pattern](https://en.wikipedia.org/wiki/Data_transfer_object) should be implemented using an API Resource class representing the public data model exposed through the API and [a custom data provider](data-providers.md). In such cases, the class marked with `@ApiResource` will act as a DTO.
However, it's sometimes useful to use a specific class to represent the input or output data structure related to an operation.
## Specifying an Input or an Output Data Representation
For a given resource class, you may want to have a different representation of this class as input (write) or output (read).
To do so, a resource can take an input and/or an output class:
```php
App\Dto\BookInput
App\Dto\BookOutput
```
The `input` attribute is used during [the deserialization process](serialization.md), when transforming the user-provided data to a resource instance.
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`.
The `input` and `output` attributes are taken into account by all the documentation generators (GraphQL and OpenAPI, Hydra).
Note that `Book` entity needs an id property. The simplest way is adding a public property called `$id`, as in the example. However, as in any other entity, you can use a private property, with getter and setter functions, and/or named it as you wish, provided you annotate it with `@ApiProperty(identifier=true)`. For instance, you could have a property called `$code`. So the `InputDataTransformer` actually transforms the isbn into a code. And then in the `OutputDataTransformer`, from this code into the name.
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 `BookOutput` class:

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.
We have the following `BookInput`:
```php
isbn = $data->isbn;
return $book;
}
/**
* {@inheritdoc}
*/
public function supportsTransformation($data, string $to, array $context = []): bool
{
// in the case of an input, the value given here is an array (the JSON decoded).
// if it's a book we transformed the data already
if ($data instanceof Book) {
return false;
}
return Book::class === $to && null !== ($context['input']['class'] ?? null);
}
}
```
We now register it:
```yaml
# api/config/services.yaml
services:
# ...
'App\DataTransformer\BookInputDataTransformer': ~
# Uncomment only if autoconfiguration is disabled
#tags: [ 'api_platform.data_transformer' ]
```
To manage the output, it's exactly the same process. For example, we have the following `BookOutput`:
```php
name = $data->name;
return $output;
}
/**
* {@inheritdoc}
*/
public function supportsTransformation($data, string $to, array $context = []): bool
{
return BookOutput::class === $to && $data instanceof Book;
}
}
```
We now register it:
```yaml
# api/config/services.yaml
services:
# ...
'App\DataTransformer\BookOutputDataTransformer': ~
# Uncomment only if autoconfiguration is disabled
#tags: [ 'api_platform.data_transformer' ]
```
## Updating a Resource with a Custom Input
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.

Now, we will update our resource by using a different input representation.
With the following `BookInput`:
```php
author = $data->author;
return $existingBook;
}
/**
* {@inheritdoc}
*/
public function supportsTransformation($data, string $to, array $context = []): bool
{
if ($data instanceof Book) {
return false;
}
return Book::class === $to && null !== ($context['input']['class'] ?? null);
}
}
```
```yaml
# api/config/services.yaml
services:
# ...
'App\DataTransformer\BookInputDataTransformer': ~
# Uncomment only if autoconfiguration is disabled
#tags: [ 'api_platform.data_transformer' ]
```
## Disabling the Input or the Output
Both the `input` and the `output` attributes can be set to `false`. If `input` is `false`, the deserialization process
will be skipped. If `output` is `false`, the serialization process will be skipped.
## Per Operation `input` and `output`
`input` and `output` attributes can be set on a per operation basis:
```php
POST
App\Dto\CreateBook
App\Dto\BookOutput
PUT
App\Dto\UpdateBook
App\Dto\BookOutput
```
## Input/Output Metadata
When specified, `input` and `output` attributes support:
- a string representing the class to use
- a falsy boolean to disable them
- an array to specify more metadata for example `['class' => BookInput::class, 'name' => 'BookInput', 'iri' => '/book_input']`
## Using Objects As Relations Inside Resources
Because API Platform 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:
```php
validator = $validator;
}
/**
* {@inheritdoc}
*/
public function transform($data, string $to, array $context = []): Book
{
$this->validator->validate($data);
$book = new Book();
$book->isbn = $data->isbn;
return $book;
}
/**
* {@inheritdoc}
*/
public function supportsTransformation($data, string $to, array $context = []): bool
{
if ($data instanceof Book) {
return false;
}
return Book::class === $to && null !== ($context['input']['class'] ?? null);
}
}
```