Основные концепции
JSON:API содержит множество концепций в своей спецификации, но не все из них задокументированы здесь. Тем не менее, пользователям модуля не нужно полностью понимать все концепции спецификации, чтобы продуктивно использовать модуль. Если вы хотите глубже разобраться в том, как устроены документы JSON:API, почему модуль работает тем или иным образом, или просто хотите больше узнать о дизайне модуля, рекомендуется ознакомиться со спецификацией на сайте jsonapi.org.
Структура документа
JSON:API строго определяет, как должны быть структурированы JSON-документы и какую информацию необходимо включать в каждое тело запроса и/или ответа.
Каждое тело запроса/ответа должно быть объектом JSON верхнего уровня.
{
// ваши данные здесь...
}
Данные, или информация, относящаяся к ресурсу или ресурсам, должны находиться внутри этого объекта верхнего уровня под "элементом" с ключом data
. Элемент — это просто предопределённый ключ в объекте JSON. Элемент data
может быть либо объектом ({}
), либо массивом ([]
). При создании или обновлении ресурса это всегда будет одиночный объект ({}
), представляющий один элемент. Только при получении "коллекции" нескольких ресурсов это свойство будет массивом.
{
"data": {
// Данные вашего ресурса здесь.
}
}
Другие элементы верхнего уровня включают: errors
, meta
, links
и included
. Из них чаще всего используется included
, но он будет рассмотрен позже в документации.
Для получения дополнительной информации о структуре верхнего уровня можно обратиться к спецификации.
Внутри элементов data
и included
находятся "объекты ресурсов" или "объекты идентификаторов ресурсов". "Объекты ресурсов" представляют собой содержимое ресурсов (сущностей), с которыми вы будете работать. "Объекты идентификаторов ресурсов" подобны внешним ключам в базе данных; они идентифицируют ресурс, не включая в себя его поля. В терминах Drupal, объект ресурса — это, как правило, JSON-представление одной сущности: узла, термина таксономии или пользователя. Снова в терминах Drupal, идентификатор ресурса содержит достаточно информации, чтобы загрузить сущность — его тип и ID, и ничего больше.
Каждый объект ресурса обязан содержать два элемента: type
и id
. Единственное исключение — при создании новой сущности, в этом случае id
можно опустить, чтобы позволить Drupal сгенерировать его. Однако клиентское приложение вполне может предоставить UUID ресурса при создании. Все ID в JSON:API являются UUID.
Элемент type
всегда обязателен. Значение для типа формируется из имени типа сущности и её подтипа (bundle), если применимо. Тип для ресурса всегда следует шаблону entity_type--bundle
. Например, для основных типов узлов article и basic page это будут: node--article
и node--page
.
Таким образом, для сущности без обязательных полей можно создать новый объект с таким JSON:
{
"data": {
"type": "node--my-bundle",
}
}
Однако это было бы не очень полезно. Нам нужно включить фактические значения для сущности. Для этого JSON:API использует два элемента: attributes
и relationships
. attributes
содержит значения, специфичные для самой сущности. relationships
— это значения, которые принадлежат другим ресурсам. В Drupal, relationships
обычно обозначает поля-ссылки на сущности. Например, в типе статьи свойство uid
— это ссылка на пользователя, который написал статью. Пример тела документа с attributes
и relationships
может выглядеть так:
{
"data": {
"type": "node--my-bundle",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"title": "Пример"
},
"relationships": {
"uid": {
"data": {
"type": "user--user",
"id": "53bb14cc-544a-4cf2-88e8-e9cdd0b6948f"
}
}
}
}
}
Как видите, свойство uid
находится под элементом relationships
. Как и основной ресурс, оно содержит type
и id
, так как это отдельный и самостоятельный ресурс.
Обратите внимание, что у uid
нет элементов attributes
или relationships
. Это потому, что JSON:API не включает содержимое связанного ресурса, если явно не запрошено с помощью специального параметра запроса include
. Подробнее об этом далее в документации (см. "Получение ресурсов (GET)").
Подробнее о структуре объектов ресурсов можно узнать в спецификации.
§ «Виртуальные» идентификаторы ресурсов
В некоторых случаях Drupal позволяет связям ссылаться на ресурс (поле-ссылка на сущность), который не хранится в базе данных и, следовательно, недоступен через JSON:API. «Виртуальный» идентификатор ресурса может означать разные ситуации в зависимости от контекста, но всегда относится к ресурсу, который не может быть найден.
Использование и значение 'виртуального' идентификатора ресурса в ядре Drupal
Поле parent
термина таксономии — самый примечательный пример этого особого случая. Это поле может содержать идентификатор ресурса для «виртуального» термина. В таком случае он указывает на термин <root>
, что сигнализирует о том, что данный термин находится на верхнем уровне иерархии словаря.
Пример ответа для гипотетического термина таксономии:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Политика"
},
"relationships": {
"parent": {
"data": [
{
"id": "virtual",
"type": "taxonomy_term--tags",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual",
"meta": {
"about": "Использование и значение 'виртуального' идентификатора ресурса."
}
}
}
}
}
]
}
}
}
}
Обратите внимание, что в этом примере свойство parent
имеет объект идентификатора ресурса, где id
не UUID, а "virtual"
. Это необходимо, потому что термин верхнего уровня ссылается на нестандартный термин <root>
(target_id = 0
).
Почему?
Поскольку корневой термин не хранится и один термин может иметь нескольких родителей, возникает важный вопрос: как отличить ситуацию, когда термин:
- имеет только термин
3
как родителя ([3]
)? - имеет и корневой термин
0
, и термин3
как родителей ([0, 3]
)?
Ответ: если бы JSON:API опустил нестандартный корневой термин 0
, а не использовал ID "virtual"
, тогда невозможно было бы различить эти два случая!
§ «Отсутствующие» идентификаторы ресурсов
Drupal не «очищает» связи, ведущие к удалённым сущностям (поля-ссылки на сущности, которые были удалены). Иными словами: Drupal оставляет «висячие» ссылки без изменений.
Когда JSON:API сталкивается с такими ссылками, он использует идентификатор ресурса "missing".
Использование и значение 'отсутствующего' идентификатора ресурса в ядре Drupal
Оставаясь в контексте поля parent
термина таксономии: представим, что данный термин ранее имел родителем термин «Бельгия», но теперь он удалён — возможно, страна Бельгия прекратила своё существование. Тогда это поле будет содержать идентификатор ресурса для «отсутствующего» термина.
Пример ответа для гипотетического термина:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Политика"
},
"relationships": {
"parent": {
"data": [
{
"id": "missing",
"type": "unknown",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#missing",
"meta": {
"about": "Использование и значение 'отсутствующего' идентификатора ресурса."
}
}
}
}
}
]
}
}
}
}
Обратите внимание, что свойство parent
имеет идентификатор ресурса, где id
— это "missing", а type
— unknown
(поскольку Drupal не хранит bundle удалённой сущности, невозможно определить имя ресурса в терминах JSON:API).
Статья с сайта Drupal Documentation.