JSONAPI - забудьте всё, чему вас учили в Drupal-школе!

jsonapi

В продолжение темы о headless-Drupal хочу рассказать о замечательнейшем модуле JSONAPI. Согласно официальному описанию, модуль является имплементацией спецификации JSON API для Drupal.. Что же представляет из себя эта спецификация? Во-первых, сам формат данных (структура полей). Во-вторых, формат запроса данных - фильтрация, необходимые поля, сортировки и т.д. Лично я считаю этот модуль крайне необходимым для построения headless-систем, ведь JSONAPI не только делает данные более удобными для разбора на фронтенде, но и существенно сокращает этап разработки бэкенда и экономит не только ваше время, но и ресурсы сервера. И вот почему:

  • вам больше не надо настраивать отображение материалов
  • вам не нужны вьюсы. Ну почти не нужны, в очень редких случаях они всё же понадобятся, но об этом ниже
  • вьюсы с сортировками и фильтрами теперь тоже не нужны.

Итак, перейдём к перечислению возможностей и преимуществ модуля.

Формат данных.

Известно, что в восьмёрке в ядре есть модуль REST, который позволяет получать в json любые материалы, но есть одно "но" - структура данных там будет приблизительно такая:

<?php
{
 
title: [
   
value: 'My node'
 
]
}
?>

С виду, ничего страшного, но в таком случае к значению поля обратиться можно будет только через "titlte[0].value". Конечно, всем, кто знаком с друпалом, знакома и эта запись, но по факту такие данные крайне неудобно разбирать в Javascript и тем более неудобно их формировать. JSONAPI делает эту структуру куда более понятной:

<?php
 
{
 
"data": {
   
"type": "node--my-bundle",
   
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
   
"attributes": {
     
"title": "An Example"
   
},
   
"relationships": {
     
"uid": {
       
"data": {
         
"type": "user--user",
         
"id": "53bb14cc-544a-4cf2-88e8-e9cdd0b6948f"
       
}
      }
    }
  }
}
?>

Как видно, данные разделены на две секции - attributes и relationships, в первой отображаются поля самой запрошенной сущности, а во второй - поля-референсы - ссылка на автора, таксономия и т.д.

Запрос нескольких сущностей

Чтобы запросить одну сущность, необходимо сделать GET-запрос на адрес вида /jsonapi/{entity_type}/{bundle}/{uuid}, например:

/jsonapi/node/article/53bb14cc-544a-4cf2-88e8-e9cdd0b6948f

Как видно,  здесь необходимо оперировать uuid, то же самое касается и PATCH- и DELETE-запросов.

Однако, если мы запросим адрес /jsonapi/node/article, то получим список всех статей. Вернее не всех, а только 50 штук, т.к. в модуле JSONAPI стоит ограничение выводить не более 50 сущностей. Но этот число можно уменьшить, просто указав в запросе параметр количества сущностей на страницу:

http://example.com/jsonapi/node/article?page[limit]=10

Чтобы получить ещё десяток статей, укажем параметр offset:

http://example.com/jsonapi/node/article?page[limit]=10&page[offset]=10

Сортировка выборки

Полученную выборку можно отсортировать по любым критериям. Тут стоит отметить, что многие параметры в JSONAPI имеют две формы записи - полную и сокращённую. Например, отсортировать статьи по дате создания можно так:

<?php
 
SHORT
sort
=created

NORMAL
sort
[sort-created][path]=created
?>

Отсортировать по имени автора в обратном порядке:

<?php
SHORT
sort
=-uid.name

NORMAL
sort
[sort-author][path]=uid.name
sort
[sort-author][direction]=DESC
?>

Отсортировать одновременно по нескольким критериям:

<?php
SHORT
sort
=-created,uid.name

NORMAL
sort
[sort-created][path]=created
sort
[sort-created][direction]=DESC
sort
[sort-author][path]=uid.name
?>

Фильтрация выборки

Параметры фильтров по своей структуре аналогичны параметрам сортировки. Вот пример для получения только опубликованных материалов:
<?php
SHORT
filter
[status][value]=1

NORMAL
filter
[status-filter][condition][path]=status
filter
[status-filter][condition][value]=1
?>

Хочу заметить, что в данном случае в краткой форме status - это системное название поля, а в полной форме status-filter - это произвольное название фильтра.

Как вы уже догадались, с помощью фильтров можно запрашивать ноды по nid, а не по uuid.

Фильтровать можно и по полям связанных сущностей, в таком случае в качестве пути фильтра пишется название поля ссылки, а через точку добавляется название поля в целевой сущности, например так выглядит фильтрация по имени автора:

<?php
SHORT
filter
[uid.name][value]=admin

NORMAL
filter
[name-filter][condition][path]=uid.name
filter
[name-filter][condition][value]=admin
?>

Также есть возможность фильтровать не только по критерию равенства, доступны операторы "IN", "NOT IN", ">", "<", "<>", "BETWEEN" и "CONTAINS". Вот пример для фильтра по нескольким именам авторов:

<?php
NORMAL
filter
[name-filter][condition][path]=uid.name
filter
[name-filter][condition][operator]=IN
filter
[name-filter][condition][value][]=admin
filter
[name-filter][condition][value][]=john
?>

Больше примеров вы найдёте здесь

Запрос связанных сущностей

По умолчанию связанные сущности не возвращаются сервером, отдаётся лишь информация о типе сущностей и их uuid в секции relationships. Однако мы можем запросить и их, просто указав параметр include в нашем запросе, например include=uid добавит в ответ сервера все поля авторов. Вернее сказать не поля, а сущности, просто они будут не в секции data, а в секции included.

Указание нужных полей

Часто нам не нужны все поля сущности. Для этого есть параметр fields. Например:

http://example.com/jsonapi/node/article/{{article_uuid}}?include=uid&fields[node--article]=title,body&fields[uid]=name

Этот запрос выдаст нам заголовок статьи, её текст и имя автора.

Итого

Как видно, Views нам действительно теперь не нужен. В принципе, теперь для сборки бэкенда на Drupal достаточно создать все нужные сущности и их поля и установить модуль jsonapi. И всё.

Что у модуля под капотом?

Говорят, что при некоторых запросах JSONAPI даже не делает полный бутстрап друпала, но я не проверял это. Как бы то ни было, по быстродействию даже на глаз видно, что модуль работает быстрее, чем views. А логирование SQL-запросов показало, что сперва делается один запрос, возвращающий айдишники сущностей, а сами сущности берутся из таблицы cache_entity. В отличие от того же views - не нужно тратить ресурсы на построение объекта самого представления.

Недостатки

  • не поддерживаются обратные референсы (например, в выборке по пользователям не получится собрать их материалы)
  • не поддерживается агрегация
  • нельзя получить за один запрос более 50 сущностей (но существуют обходные пути - параллельные запросы либо модуль Subrequests)

Первые два недостатка порой весьма критичны, причём их никогда не пофиксят, ибо это подразумевается в самом стандарте спецификации JSONAPI. Тем не менее, с такими запросами легко справляется Views, именно поэтому я и писал, что он почти не нужен.

PS: данная статья не является переводом официальной документации, хоть и содержит выдержки из неё. Для тех, кто хочет узнать больше, рекомендую следующие ссылки:

Страница модуля: https://www.drupal.org/project/jsonapi

Официальная документация: https://www.drupal.org/docs/8/modules/json-api

Видеоуроки на YouTube: https://www.youtube.com/playlist?list=PLZOQ_ZMpYrZsyO-3IstImK1okrpfAjuMZ - это реально круто!

Спецификация стандарта: http://jsonapi.org/

PPS: дичайше прошу прощения за то, что почти все примеры заключены в тэги php, просто никак руки не дойдут сделать нормальную подсветку кода)) Естественно, во всей этой статье в примерах нет ни одной строк php-кода.

Поделиться: