Skill serialization-groups
Mengonfigurasi konteks serialisasi dan denormalisasi menggunakan groups untuk mengontrol visibilitas field dan embedding relasi di API Platform.
- Bintang GitHub
- 29
- File
- 1
- Commit terakhir
- 22 Okt 2026
- Lisensi
- —
- Tool yang diizinkan
- —
Apa fungsi skill serialization-groups?
serialization-groups adalah agent skill. Mengonfigurasi konteks serialisasi dan denormalisasi menggunakan groups untuk mengontrol visibilitas field dan embedding relasi di API Platform.
Ringkasan dibuat dari SKILL.md skill ini.
Tentang skill serialization-groups
Mengelola visibilitas field dan embedding relasi di API Platform adalah hal yang dimungkinkan oleh skill ini bagi developer yang bekerja dengan Symfony atau Laravel. Skill ini menyediakan logika untuk mengonfigurasi konteks normalisasi dan denormalisasi, sehingga Anda dapat mengontrol property mana yang muncul dalam output JSON saat pembacaan atau input saat penulisan. Dengan menggunakan attribute #[Groups], Anda dapat menentukan aturan visibilitas spesifik untuk berbagai operasi, seperti menampilkan detail yang lebih lengkap pada view single item dibandingkan pada list koleksi.
Seorang agent harus memuat skill ini ketika developer perlu melakukan debug pada field JSON yang hilang, mengimplementasikan property write-only seperti password, atau mengelola bagaimana entity terkait di-embed sebagai object versus IRI. Skill ini menangani skenario kompleks seperti override per-property menggunakan attribute #[Context] untuk mengubah format tanggal atau nested serialization groups. Skill ini juga memberikan panduan spesifik bagi pengguna Laravel yang harus menggunakan #[ApiProperty] karena Eloquent model tidak memiliki typed properties. Pendekatan ini ditujukan untuk menjaga konsistensi pada codebase yang sudah ada di mana penggunaan DTO split mungkin tidak diperlukan.
Apa yang bisa dilakukan agent dengannya
- 1Kontrol visibilitas field per operasiKonfigurasikan tampilan koleksi yang ringkas sambil menyediakan dataset yang lebih kaya untuk request item individual.
- 2Kelola property write-onlyPastikan data sensitif seperti password dapat diterima saat input tetapi tidak pernah terekspos dalam respons API.
- 3Beralih antara embedded objects dan IRITentukan apakah entity terkait harus muncul sebagai nested object lengkap atau hanya sebagai referensi string sederhana.
- 4Terapkan formatting spesifik pada propertyTimpa pengaturan serialisasi default untuk satu field tertentu, seperti mengubah format tanggal.
Ditulis dari SKILL.md milik skill tersebut. Setiap use case diverifikasi dengan kutipan darinya.
Cara install skill serialization-groups
Setiap perintah menyalin folder skill ke direktori skills client. Restart client atau mulai sesi baru untuk memuatnya.Install skill serialization-groups di Plugin
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Install skill serialization-groups di Claude Code
~/.claude/skills/serialization-groups/SKILL.md
$ npx degit api-platform/skillset/skills/serialization-groups ~/.claude/skills/serialization-groupsInstall skill serialization-groups di Claude Code (project)
.claude/skills/serialization-groups/SKILL.md
$ npx degit api-platform/skillset/skills/serialization-groups .claude/skills/serialization-groupsInstall skill serialization-groups di Codex
~/.agents/skills/serialization-groups/SKILL.md
$ npx degit api-platform/skillset/skills/serialization-groups ~/.agents/skills/serialization-groupsInstall skill serialization-groups di Gemini CLI
~/.gemini/skills/serialization-groups/SKILL.md
$ npx degit api-platform/skillset/skills/serialization-groups ~/.gemini/skills/serialization-groupsInstall skill serialization-groups di Claude.ai
npx degit api-platform/skillset/skills/serialization-groups serialization-groups && zip -r serialization-groups.zip serialization-groups # claude.ai → Customize → Skills → + → Create skill → Upload a skill → serialization-groups.zip
SKILL.md
Lihat di GitHubSerialization Groups
Prefer one resource class per representation over groups for new designs. Before reaching for groups, consider a DTO split: one class per output shape and per input shape, each with a flat, explicit set of properties (see api-resource). Reasons groups are a poor default:
- The public shape becomes implicit and scattered. To know what
GET /booksreturns you must mentally union every#[Groups]tag across the class hierarchy and cross-reference each operation'snormalizationContext. A dedicatedBookOutputDTO states the shape in one place.- They complicate the metadata. Per-operation contexts, per-property
#[Context], and group inheritance interact in ways that are hard to predict and hard to test.- They block streaming serialization. API Platform's JsonStreamer path needs one static shape per class; a class whose output varies by group can't be streamed and falls back to the slower object normalizer.
Use groups when: you're working in an existing codebase already built on them (stay consistent), or a DTO split is genuinely overkill (one tiny read/write asymmetry on an internal resource). Otherwise, split the class.
The two contexts
normalizationContext governs reading (entity → JSON). denormalizationContext
governs writing (JSON → entity). A property is only serialized/deserialized if
one of its #[Groups] is listed in the active context.
use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
normalizationContext: ['groups' => ['book:read']],
denormalizationContext: ['groups' => ['book:write']],
)]
class Book
{
#[Groups(['book:read'])] // appears in output, ignored on input
public ?int $id = null;
#[Groups(['book:read', 'book:write'])] // read and write
public string $title = '';
#[Groups(['book:write'])] // write-only, e.g. a password
public ?string $secret = null;
}
A property with no group in the active context is invisible: a field present on the entity but absent from the response is almost always a missing read group.
Naming convention
Use resource:operation-style group names — book:read, book:write,
book:item:read. This keeps groups namespaced per resource so a read group on
one class never accidentally pulls properties on another. Pairing a broad
book:read with a narrower book:item:read lets item operations expose more than
collections (see next section).
Per-operation contexts
Override the resource-level context on a single operation. Common pattern: a lean collection, a richer item view.
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
#[ApiResource(normalizationContext: ['groups' => ['book:read']])]
#[GetCollection] // book:read only
#[Get(normalizationContext: ['groups' => ['book:read', 'book:item:read']])]
#[Patch(denormalizationContext: ['groups' => ['book:write']])]
class Book
{
#[Groups(['book:read'])]
public string $title = '';
#[Groups(['book:item:read'])] // only on the single-item GET
public ?string $description = null;
}
Controlling embedded relations
A relation is embedded as a full object when the related class has a property in a group shared with the parent's context; otherwise it serializes as an IRI/string. This is how you choose embed-vs-reference:
#[ApiResource(normalizationContext: ['groups' => ['book:read']])]
class Book
{
#[Groups(['book:read'])]
public ?Author $author = null; // embedded only if Author has a 'book:read' property
}
class Author
{
#[Groups(['book:read'])]
public string $name = ''; // this property pulls Author inline
}
Drop the book:read group from Author::$name and author collapses back to an
IRI. This implicit coupling is exactly the kind of thing a DTO split makes explicit.
Per-property context override with #[Context]
#[Context] overrides serializer options for one property without a new group —
useful for date formats or switching the normalization group on a single relation
(embed the same related type at two depths):
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
class Book
{
#[Groups(['book:read'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
public ?\DateTimeInterface $publishedAt = null;
#[Groups(['book:read'])]
#[Context(['normalization' => ['groups' => ['author:summary']]])]
public ?Author $author = null; // serialized with author:summary, not book:read
}
The normalization/denormalization keys scope the override to one direction. See
the parallel example in state-provider (Per-Property Serialization Context).
Interaction with other features
- Validation groups are separate from serialization groups — don't reuse the
same names expecting them to align. See operations for
validationContext. securityexpressions on properties (security: "is_granted(...)") gate fields independently of groups; both must pass.
Laravel (Eloquent)
API Platform uses the Symfony Serializer on Laravel too, so normalizationContext /
denormalizationContext, the two-context model, per-operation contexts and embed-vs-IRI
behaviour are identical. The one difference: Eloquent models have no typed
properties, so #[Groups] can't be attached per property. Declare groups at the
class level via #[ApiProperty(serialize: …, property: …)]:
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(normalizationContext: ['groups' => ['book:read']])]
#[ApiProperty(serialize: new Groups(['book:read']), property: 'title')]
#[ApiProperty(serialize: new Groups(['book:read']), property: 'author')]
class Book extends Model {}
DTO/ApiResource classes (not extending Model) use property-level #[Groups] as
shown above. The name_converter (default SnakeCaseToCamelCaseNameConverter) is set
in config/api-platform.php.
Checklist
- Considered a DTO-per-shape split before adding groups (see api-resource)
- Group names namespaced per resource (
book:read, not bareread) - Write-only secrets carry only the write group
- Embedded-vs-IRI relations verified against actual JSON, not assumed
-
#[Context]used for one-off format/group tweaks instead of a whole new group
Berkas dalam skill ini
1Pertanyaan seputar skill serialization-groups
Bagaimana cara install skill serialization-groups di Claude Code?
Jalankan npx degit api-platform/skillset/skills/serialization-groups ~/.claude/skills/serialization-groups. Claude Code memuat skill dari ~/.claude/skills (semua proyek) atau .claude/skills (satu proyek) dan menggunakan skill saat deskripsinya cocok dengan tugas.
Client mana saja yang bisa menggunakan skill serialization-groups?
Client apa pun yang membaca format Agent Skills: Claude Code, Codex, Gemini CLI, dan claude.ai (unggah sebagai ZIP). Script dalam skill hanya berjalan di client yang mengizinkan eksekusi kode.
Apa perbedaan antara normalizationContext dan denormalizationContext?
normalizationContext mengatur proses pembacaan (entity ke JSON), sedangkan denormalizationContext mengatur proses penulisan (JSON ke entity).
Bagaimana cara mengontrol apakah sebuah relasi akan di-embed sebagai object atau dikembalikan sebagai IRI?
Sebuah relasi akan di-embed sebagai object lengkap jika class terkait memiliki property dalam group yang sama dengan context parent; jika tidak, maka akan diserialisasi sebagai IRI.
Apakah saya harus selalu menggunakan serialization groups untuk desain baru?
Tidak, untuk desain baru sebaiknya Anda lebih memilih satu resource class per representasi (DTO split) daripada menggunakan groups untuk menghindari kompleksitas metadata dan bentuk data yang implisit.
Bagaimana cara menerapkan pengaturan serialisasi spesifik pada satu property saja?
Anda dapat menggunakan attribute #[Context] untuk menimpa (override) opsi serializer pada satu property tertentu, seperti format tanggal atau normalization groups yang spesifik.