Skip to content

Commit ec3fefd

Browse files
committed
feat: add support for normalization/denormalization with attributes
1 parent 8dc8c8d commit ec3fefd

File tree

1 file changed

+335
-0
lines changed

1 file changed

+335
-0
lines changed

core/serialization.md

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,341 @@ the specific configuration for this operation.
389389

390390
Refer to the [operations](operations.md) documentation to learn more.
391391

392+
## Using Serialization Attributes
393+
394+
In addition to using serialization groups, you can specify which attributes (properties) of a
395+
resource should be exposed during normalization (read) and denormalization (write) processes. This
396+
is done through the `attributes` key in the serialization context.
397+
398+
It is simple to specify which attributes to use in the API system:
399+
400+
1. Add the normalization context and denormalization context to the resource, and specify which
401+
attributes to expose.
402+
2. You can specify nested attributes for related objects using array syntax.
403+
404+
<code-selector>
405+
406+
```php
407+
<?php
408+
// api/src/ApiResource/Book.php with Symfony or app/ApiResource/Book.php with Laravel
409+
namespace App\ApiResource;
410+
411+
use ApiPlatform\Metadata\ApiResource;
412+
413+
#[ApiResource(
414+
normalizationContext: [
415+
'attributes' => ['id', 'title', 'author' => ['name']],
416+
],
417+
denormalizationContext: [
418+
'attributes' => ['title', 'author' => ['name']],
419+
],
420+
)]
421+
class Book
422+
{
423+
public ?int $id = null;
424+
425+
public string $title = '';
426+
427+
public Author $author;
428+
429+
public string $isbn = '';
430+
431+
// ...
432+
}
433+
```
434+
435+
```yaml
436+
# The YAML syntax is only supported for Symfony
437+
# api/config/api_platform/resources/Book.yaml
438+
App\ApiResource\Book:
439+
normalizationContext:
440+
attributes: ['id', 'title', 'author' => ['name']]
441+
denormalizationContext:
442+
attributes: ['title', 'author' => ['name']]
443+
```
444+
445+
```xml
446+
<!-- The XML syntax is only supported for Symfony -->
447+
<!-- api/config/api_platform/resources.xml -->
448+
<?xml version="1.0" encoding="UTF-8" ?>
449+
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
450+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
451+
xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
452+
https://api-platform.com/schema/metadata/resources-3.0.xsd">
453+
<resource class="App\ApiResource\Book">
454+
<normalizationContext>
455+
<values>
456+
<value name="attributes">
457+
<values>
458+
<value>id</value>
459+
<value>title</value>
460+
<value key="author">
461+
<values>
462+
<value>name</value>
463+
</values>
464+
</value>
465+
</values>
466+
</value>
467+
</values>
468+
</normalizationContext>
469+
<denormalizationContext>
470+
<values>
471+
<value name="attributes">
472+
<values>
473+
<value>title</value>
474+
<value key="author">
475+
<values>
476+
<value>name</value>
477+
</values>
478+
</value>
479+
</values>
480+
</value>
481+
</values>
482+
</denormalizationContext>
483+
</resource>
484+
</resources>
485+
```
486+
487+
</code-selector>
488+
489+
<code-selector>
490+
491+
```php
492+
<?php
493+
// api/src/ApiResource/Author.php with Symfony or app/ApiResource/Author.php with Laravel
494+
namespace App\ApiResource;
495+
496+
use ApiPlatform\Metadata\ApiResource;
497+
498+
#[ApiResource]
499+
class Author
500+
{
501+
public ?int $id = null;
502+
503+
public string $name;
504+
505+
// ...
506+
}
507+
```
508+
509+
```yaml
510+
# The YAML syntax is only supported for Symfony
511+
# api/config/api_platform/resources/Author.yaml
512+
App\ApiResource\Author: ~
513+
```
514+
515+
```xml
516+
<!-- The XML syntax is only supported for Symfony -->
517+
<!-- api/config/api_platform/resources.xml -->
518+
<?xml version="1.0" encoding="UTF-8" ?>
519+
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
520+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
521+
xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
522+
https://api-platform.com/schema/metadata/resources-3.0.xsd">
523+
<resource class="App\ApiResource\Author" />
524+
</resources>
525+
```
526+
527+
</code-selector>
528+
529+
In the previous example, the `id`, `title` properties and the nested `author.name` will be visible
530+
when reading (`GET`) the object. When writing (`PUT` / `PATCH` / `POST`), only `title` and
531+
`author.name` are accepted. The `isbn` property is never exposed because it was not specified in the
532+
attributes list.
533+
534+
Internally, API Platform passes the value of the `normalizationContext` as the 3rd argument of
535+
[the `Serializer::serialize()` method](https://api.symfony.com/master/Symfony/Component/Serializer/SerializerInterface.html#method_serialize)
536+
during the normalization process. `denormalizationContext` is passed as the 4th argument of
537+
[the `Serializer::deserialize()` method](https://api.symfony.com/master/Symfony/Component/Serializer/SerializerInterface.html#method_deserialize)
538+
during denormalization (writing).
539+
540+
In addition to the `attributes` key, you can configure any Symfony Serializer option through the
541+
`$context` parameter (e.g. the `enable_max_depth` key when using
542+
[the `@MaxDepth` annotation](https://symfony.com/doc/current/components/serializer.html#handling-serialization-depth)).
543+
544+
Any attributes configuration that you specify will also be leveraged by the built-in actions and the
545+
OpenAPI documentation generator.
546+
547+
## Using Serialization Attributes per Operation
548+
549+
It is possible to specify normalization and denormalization contexts (as well as any other
550+
attribute) on a per-operation basis. API Platform will always use the most specific definition. For
551+
instance, if normalization attributes are set both at the resource level and at the operation level,
552+
the configuration set at the operation level will be used and the resource level ignored.
553+
554+
In the following example we use different attributes for the `GET` and `POST` operations:
555+
556+
<code-selector>
557+
558+
```php
559+
<?php
560+
// api/src/ApiResource/Book.php with Symfony or app/ApiResource/Book.php with Laravel
561+
namespace App\ApiResource;
562+
563+
use ApiPlatform\Metadata\ApiResource;
564+
use ApiPlatform\Metadata\Get;
565+
use ApiPlatform\Metadata\Post;
566+
567+
#[ApiResource]
568+
#[Get(
569+
normalizationContext: [
570+
'attributes' => ['id', 'title', 'author' => ['name']],
571+
],
572+
)]
573+
#[Post(
574+
denormalizationContext: [
575+
'attributes' => ['title', 'name', 'author' => ['name']],
576+
],
577+
normalizationContext: [
578+
'attributes' => ['id', 'title', 'author' => ['id', 'name']],
579+
],
580+
)]
581+
class Book
582+
{
583+
public ?int $id = null;
584+
585+
public string $title = 'The book title';
586+
587+
public ?string $name = null;
588+
589+
public Author $author;
590+
591+
public string $isbn = '978-3-16-148410-0';
592+
593+
// ...
594+
}
595+
```
596+
597+
```yaml
598+
# The YAML syntax is only supported for Symfony
599+
# api/config/api_platform/resources/Book.yaml
600+
App\ApiResource\Book:
601+
operations:
602+
ApiPlatform\Metadata\Get:
603+
normalizationContext:
604+
attributes: ['id', 'title', 'author' => ['name']]
605+
ApiPlatform\Metadata\Post:
606+
denormalizationContext:
607+
attributes: ['title', 'name', 'author' => ['name']]
608+
normalizationContext:
609+
attributes: ['id', 'title', 'author' => ['id', 'name']]
610+
```
611+
612+
```xml
613+
<!-- The XML syntax is only supported for Symfony -->
614+
<!-- api/config/api_platform/resources.xml -->
615+
<?xml version="1.0" encoding="UTF-8" ?>
616+
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
617+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
618+
xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
619+
https://api-platform.com/schema/metadata/resources-3.0.xsd">
620+
<resource class="App\ApiResource\Book">
621+
<operations>
622+
<operation class="ApiPlatform\Metadata\Get">
623+
<normalizationContext>
624+
<values>
625+
<value name="attributes">
626+
<values>
627+
<value>id</value>
628+
<value>title</value>
629+
<value key="author">
630+
<values>
631+
<value>name</value>
632+
</values>
633+
</value>
634+
</values>
635+
</value>
636+
</values>
637+
</normalizationContext>
638+
</operation>
639+
<operation class="ApiPlatform\Metadata\Post">
640+
<denormalizationContext>
641+
<values>
642+
<value name="attributes">
643+
<values>
644+
<value>title</value>
645+
<value>name</value>
646+
<value key="author">
647+
<values>
648+
<value>name</value>
649+
</values>
650+
</value>
651+
</values>
652+
</value>
653+
</values>
654+
</denormalizationContext>
655+
<normalizationContext>
656+
<values>
657+
<value name="attributes">
658+
<values>
659+
<value>id</value>
660+
<value>title</value>
661+
<value key="author">
662+
<values>
663+
<value>id</value>
664+
<value>name</value>
665+
</values>
666+
</value>
667+
</values>
668+
</value>
669+
</values>
670+
</normalizationContext>
671+
</operation>
672+
</operations>
673+
</resource>
674+
</resources>
675+
```
676+
677+
</code-selector>
678+
679+
<code-selector>
680+
681+
```php
682+
<?php
683+
// api/src/ApiResource/Author.php with Symfony or app/ApiResource/Author.php with Laravel
684+
namespace App\ApiResource;
685+
686+
use ApiPlatform\Metadata\ApiResource;
687+
688+
#[ApiResource]
689+
class Author
690+
{
691+
public ?int $id = null;
692+
693+
public string $name;
694+
695+
// ...
696+
}
697+
```
698+
699+
```yaml
700+
# The YAML syntax is only supported for Symfony
701+
# api/config/api_platform/resources/Author.yaml
702+
App\ApiResource\Author: ~
703+
```
704+
705+
```xml
706+
<!-- The XML syntax is only supported for Symfony -->
707+
<!-- api/config/api_platform/resources.xml -->
708+
<?xml version="1.0" encoding="UTF-8" ?>
709+
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
710+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
711+
xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
712+
https://api-platform.com/schema/metadata/resources-3.0.xsd">
713+
<resource class="App\ApiResource\Author" />
714+
</resources>
715+
```
716+
717+
</code-selector>
718+
719+
The `id`, `title` and `author.name` attributes will be included in the document generated during a
720+
`GET` operation because the operation-specific configuration is used. However the document generated
721+
when a `POST` request will be received will only include `id`, `title`, and `author` with `id` and
722+
`name` in the response because of the specific configuration for this operation. The `POST` request
723+
input accepts `title`, `name`, and `author.name`.
724+
725+
Refer to the [operations](operations.md) documentation to learn more.
726+
392727
## Embedding Relations
393728

394729
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/relations?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Relations screencast"><br>Watch the Relations screencast</a></p>

0 commit comments

Comments
 (0)