Relations 

Relations are resolved automatically from the TCA schema. By default, related records are serialized as plain IRI strings:

{
    "color_id": "/_api/colors/1",
    "categories": [
        "/_api/categories/5",
        "/_api/categories/8"
    ]
}
Copied!

This format is compatible with API Platform Admin and other Hydra clients that resolve IRIs on demand. To inline the full related record instead, see Embedding related records below.

Controlling recursion depth 

Control recursion depth with 'embed' => ['depth' => 2]. The default depth is 1.

'columns' => [
    'color_id' => ['embed' => ['depth' => 2]],
],
Copied!

Multi-table group fields 

TCA type=group fields with multiple allowed tables store relations in the prefixed tablename_uid format (e.g. pages_1,sys_file_3). These fields support embedding just like single-table relations:

// TCA definition
'related_items' => [
    'label' => 'Related Items',
    'config' => [
        'type' => 'group',
        'allowed' => 'tx_myext_domain_model_article,tx_myext_domain_model_color',
    ],
],

// API resource configuration
'columns' => [
    'related_items' => ['groups' => ['list', 'show'], 'embed' => true],
],
Copied!

The embedded response contains full objects from different tables, each with its own @type and fields:

{
    "related_items": [
        {
            "@id": "/_api/articles/201",
            "@type": "Article",
            "uid": 201,
            "title": "Related Article"
        },
        {
            "@id": "/_api/colors/1",
            "@type": "Color",
            "uid": 1,
            "name": "Red"
        }
    ]
}
Copied!

Each referenced table is resolved to its registered API resource. When no resource is registered for a table, a default-mode config is synthesized automatically (all TCA columns exposed).

Bulk preloading is fully supported: collection requests issue one SELECT per referenced table regardless of how many parent rows exist, avoiding N+1 queries.

Writing nested objects 

When a create or update request contains a related record as an object (rather than a UID), TCA_API creates the child record in-line. The child table must have a registered resource in the API registry; a nested object for an unregistered table is rejected with 422 and an UNRESOLVABLE_RELATION violation naming the column and the table.

Passing an existing UID or IRI never needs a registered child resource, so linking is unaffected.

Nested writes without a child resource 

A child table that should not be reachable as a resource of its own does not need one. Declare nestedWrite on the parent column instead — it states the role required to create through that relation, and the child's shape is derived from TCA:

use MaikSchneider\TcaApi\Enum\AccessRole;

'columns' => [
    'note_id' => [
        'groups'      => ['list', 'show', 'create'],
        'nestedWrite' => AccessRole::FE_USER,
    ],
],
Copied!

nestedWrite accepts the same shapes as a security entry: an AccessRole, an [AccessRole, groupIds] tuple, or a [class-string, method-string] callable.

When the child table is registered, nestedWrite still wins for the access check — who may write through a relation is a narrower question than what the child resource permits on its own endpoint — while columns, validation and ownership continue to come from the registered resource.

{
    "title": "My Article",
    "color_id": { "name": "Red" }
}
Copied!

By default the child resource is looked up by the foreign table name from TCA. When multiple resources are registered for the same DB table, use the resourceName column option to pin the lookup to a specific resource:

'columns' => [
    'color_id' => [
        'groups'       => ['list', 'show', 'create', 'update'],
        'resourceName' => 'colors',   // look up "colors" resource, not by table
    ],
],
Copied!

This also controls which resource's security.create role is enforced on the nested write and which resource's column config is used for validation.

Supported relation types 

TCA type Default output Embedding
select / group UID list (1,2,3) — single table → IRI strings Yes
select / group Prefixed list (table_uid) — multi-table → IRI strings Yes
inline / select foreign_field back-reference → IRI strings Yes
Any + MM Intermediate MM table → IRI strings Yes
type=group + MM Column holds count, relations in MM → IRI strings Yes