API field format¶
A compound is a field on the host resource. Its value is a list of objects keyed
by sub-field machine name. JSON:API exposes it in data.attributes, including
when its sub-fields reference other entities.
Enable JSON:API or core REST as needed, with the site's normal authentication, permissions and write-access configuration.
Read a conference¶
GET /jsonapi/node/conference/{uuid}
Accept: application/vnd.api+json
A Sessions field can appear in the response like this:
{
"field_sessions": [
{
"title": {"value": "Opening keynote"},
"topics": [{"value": "Community"}, {"value": "Accessibility"}],
"track": {
"target_id": 57,
"target_type": "taxonomy_term",
"target_uuid": "0eff320f-68b8-4cf8-b88c-5887655e4988",
"url": "/taxonomy/term/57",
"data": {
"type": "taxonomy_term--tags",
"id": "0eff320f-68b8-4cf8-b88c-5887655e4988",
"meta": {"drupal_internal__target_id": 57}
}
}
}
]
}
Sub-field properties come from their Drupal field types.
| Field setting or value | JSON shape |
|---|---|
| Outer compound field | Always a list of items |
| Sub-field capped at one | Its field type's item object, or null when empty |
| Sub-field capped above one | A list, even with one value; [] when empty |
| Nested compound | The same rules applied inside the parent item |
| Sub-field the account may not view | Its empty shape: null, or [] when capped above one; it cannot be replaced through the API |
| Entirely empty compound item | Removed when the entity is saved |
Create or replace values¶
Send a POST to /jsonapi/node/conference to create content. For PATCH, include
the existing resource UUID as data.id and use its individual resource URL:
PATCH /jsonapi/node/conference/{uuid}
Content-Type: application/vnd.api+json
{
"data": {
"type": "node--conference",
"id": "REPLACE-WITH-CONFERENCE-UUID",
"attributes": {
"field_sessions": [
{
"title": {"value": "Opening keynote"},
"topics": [{"value": "Community"}],
"track": {
"target_uuid": "0eff320f-68b8-4cf8-b88c-5887655e4988"
}
}
]
}
}
}
Sending the field replaces its item list. It does not merge one session or sub-field into the old value. Include every item and value you want to keep. For creation, also provide the host's required fields, such as its title.
References accept a valid target_id or target_uuid. The target must exist
and match the reference settings. UUID input resolves to the local entity ID.
A scalar can set a field type's main property: "title": "Opening keynote"
sets the string value. Use object form for fields with several properties.
Omitted sub-fields become empty; null clears a sub-field the account may
view. Computed values, such as processed and url, need not be sent.
Datetime sub-fields accept their serialized RFC3339 value; date-only fields
use Y-m-d.
Changing, clearing or dropping a sub-field without edit access returns 403 and saves nothing. Sending its stored value unchanged is allowed. If a sub-field with a stored value is hidden from the account, replacing the containing field is refused even with edit access. Its empty wire shape cannot distinguish preservation from deletion.
Validation errors name the sub-field path, such as
/data/attributes/field_sessions/0/title. JSON:API rejects unknown sub-field
names. Correct the value and resend the complete field.
Follow a reference¶
The reference's data.type and data.id identify its JSON:API resource.
Find the collection URL in the JSON:API root document, then request that
resource by UUID.
References inside compounds are not JSON:API relationship fields.
include=field_sessions.track is unsupported. Fetch the referenced
resource separately. Its own fields are not embedded in the compound attribute.
The data member is present when JSON:API is enabled. It can be null
when the target has no addressable JSON:API resource.
Filter and sort¶
Use nested property paths:
GET /jsonapi/node/conference?filter[field_sessions.title.value]=Opening%20keynote
GET /jsonapi/node/conference?sort=field_sessions.title.value
GET /jsonapi/node/conference?filter[field_sessions.track.target_id]=57
A sub-field's main property can be omitted, so field_sessions.title also
addresses its string value. A field delta can precede the sub-field,
such as field_sessions.0.title.value.
Descend through nested compounds by name. A capped sub-field requires an explicit
zero-based slot immediately after its name, for example
field_sessions.tags.1.value. Nesting, slots and host deltas can be combined:
field_sessions.0.speakers.1.contact.email.value selects the second speaker's
email in the first session. The leaf main property can still be omitted after
the slot. Prefix a sort path with - for descending order.
Use these public paths even when storage uses hashed column identifiers. Direct flattened storage-column paths remain accepted for compatibility.
Queries cannot stop at the whole compound, follow its reference into the target's fields, or inspect keys inside a serialized column. Those paths return a bad request. Filter references by target ID.
Read a draft or historical revision¶
Use resourceVersion=id:<revision> to select a historical host revision, or
resourceVersion=rel:working-copy for its latest draft. Normal access
permissions still apply. Compound values use the same nested format on those
versions and on translated resources.
REST, imports and upgrades¶
Core REST uses the same nested field values inside its own entity envelope. The serializer can normalize a compound field directly:
$values = \Drupal::service('serializer')
->normalize($node->get('field_sessions'), 'json');
Ordinary Migrate destinations and direct Field API writes accept storage values instead. Use the Migrate guide for reference and date mappings.