Drupal как headless CMS: рабочие приёмы для продакшена
Headless-режим в Drupal убирает привязку контента к Twig, но добавляет проблемы с кешем, предпросмотром, авторизацией и CORS. Разбираем практическую связку Drupal 10.3–11 и фронтенда через JSON:API.

Headless Drupal обычно ломается не на первом запросе к JSON:API, а позже: редактор не видит предпросмотр, CDN отдаёт старую статью, а фронтенд получает 403 после включения авторизации. Ниже — рабочие приёмы для Drupal 10.3–11, когда Drupal отвечает за контент и права, а сайт собирается отдельным приложением.
Сначала определите границу между Drupal и фронтендом
В headless-схеме Drupal не рендерит страницу через Twig. Он хранит материалы, медиа, таксономию и пользователей, а фронтенд запрашивает эти данные по API. Это не просто «выключить тему»: меняется ответственность за маршруты, кеширование, SEO, предпросмотр и обработку ошибок.
До начала работы зафиксируйте контракт:
- какие типы материалов доступны публично;
- какие поля обязательны и в каком формате приходят;
- кто отвечает за сортировку, пагинацию и фильтры;
- как фронтенд узнаёт об изменении публикации;
- какие операции требуют авторизации.
Если этого не сделать, Drupal быстро превращается в неформальную базу данных: фронтенд начинает зависеть от названий полей, внутренних идентификаторов и случайного порядка элементов.
Главный контракт headless-проекта — не URL API, а согласованная модель контента и правила её изменения.
Сноска. Headless CMS — система управления контентом без собственного пользовательского интерфейса сайта. CMS хранит и выдаёт данные, а отдельное приложение отвечает за отображение.
Выбирайте API по задаче, а не по моде
Для большинства публичных материалов в Drupal 10.3–11 достаточно встроенного модуля JSON:API. Он создаёт маршруты для сущностей и полей, поэтому не приходится писать отдельный контроллер для каждой статьи. GraphQL и REST полезны, когда нужен другой контракт, но цена поддержки у них выше.
| Подход | Когда подходит | Цена решения |
|---|---|---|
| JSON:API | Статьи, страницы, медиа, списки сущностей с типовой структурой | Меньше собственного кода, но фронтенду нужно знать структуру JSON:API и разбираться с включёнными связями |
| REST в Drupal | Небольшой набор операций с точно заданным форматом ответа | Больше ручной настройки и кода; изменение ответа становится задачей разработчика API |
| GraphQL | Сложные экраны, где клиенту нужны разные срезы данных | Нужно поддерживать схему и отдельный модуль; ошибки запросов и авторизации сложнее диагностировать |
Критерий простой: если фронтенду нужны обычные сущности Drupal и их связи, начинайте с JSON:API. Если один и тот же экран собирается из десятков источников и клиент должен выбирать поля сам, оцените GraphQL. Не добавляйте GraphQL только ради уменьшения числа HTTP-запросов: это может усложнить кеширование и контроль доступа.
Моделируйте контент под экран, но не под один экран
Частая ошибка — создать тип материала «Главная страница» с десятками полей вроде block_1_title, block_2_image и block_3_link. Такая модель быстро привязывает API к текущему дизайну. После редизайна придётся менять и Drupal, и фронтенд.
Практичнее разделить контент на повторно используемые сущности: статья, автор, изображение, карточка ссылки, промо-блок. Для составных страниц можно использовать Paragraphs, но у такого решения есть цена: фронтенд получает вложенную структуру, которую нужно нормализовать и валидировать.
Что проверить в модели
- У каждого поля есть понятное назначение, формат и правило обязательности.
- Ссылки на медиа возвращают не только внутренний идентификатор, но и данные, которые действительно нужны интерфейсу.
- Для дат заранее определены часовой пояс и формат.
- Списки не зависят от положения элемента в ответе: сортировка задана явно.
- Удаление или снятие с публикации не приводит к падению страницы на фронтенде.
Схему полей лучше описать в репозитории рядом с кодом клиента. Экспорт конфигурации Drupal не заменяет документацию: он показывает настройки сайта, но не объясняет, какие поля критичны для приложения.
Запрашивайте JSON:API предсказуемо
Базовый путь для типа материала имеет вид /jsonapi/node/article, но машинное имя типа и поля у конкретного проекта могут отличаться. Не зашивайте такие URL десятками строк по приложению: соберите небольшой слой API-клиента, где находятся базовый адрес, фильтры, пагинация и обработка ошибок.
async function loadArticles(apiBaseUrl, pageNumber = 0) {
const params = new URLSearchParams({
'filter[status]': '1',
'sort': '-created',
'page[limit]': '12',
'page[offset]': String(pageNumber * 12),
'include': 'field_image,uid'
});
const response = await fetch(
`${apiBaseUrl}/jsonapi/node/article?${params.toString()}`,
{
headers: { Accept: 'application/vnd.api+json' }
}
);
if (!response.ok) {
throw new Error(`Drupal API returned ${response.status}`);
}
return response.json();
}
Фрагмент рассчитан на браузерный JavaScript и JSON:API Drupal 10.3–11. Имена article, field_image и uid замените на машинные имена вашего сайта. Параметр include уменьшает число запросов к связанным сущностям, но увеличивает размер ответа, поэтому измеряйте не только количество запросов, но и объём JSON.
Не считайте любой ответ с HTTP 200 успешным результатом для интерфейса. Проверьте наличие нужного типа материала, связи с медиа и обязательных атрибутов. В продакшене полезно логировать URL без персональных данных, HTTP-код, время ответа и размер ответа.
Кешируйте не только страницу
В headless-схеме есть минимум два кеша: кеш ответа Drupal и кеш фронтенда или CDN. Если статья изменилась в Drupal, но клиент продолжает отдавать старый HTML, проблема может находиться на любом из этих уровней.
Для публичного контента используйте короткоживущий кеш на чтение и продумайте инвалидацию после публикации. Кеш Drupal учитывает зависимости сущностей и тегов, но внешний CDN не обязан знать, что статья связана с конкретным ответом JSON:API. Поэтому фронтенду нужен один из явных механизмов:
- короткий TTL для API и страниц;
- очистка конкретных URL после публикации;
- перегенерация только затронутых маршрутов;
- версионирование данных или запроса, если архитектура это допускает.
Не очищайте весь CDN после каждого изменения материала без измерений. Это снижает попадание в кеш и увеличивает нагрузку на Drupal. Отдельно проверьте списки: изменение одной статьи может менять выдачу раздела, RSS или страницу поиска.
Разведите публичный доступ, редактуру и предпросмотр
Публичная выдача и редакторский доступ — разные контуры. Публичный JSON:API должен возвращать только опубликованные сущности. Предпросмотр неопубликованного материала требует авторизованного запроса и отдельного решения на фронтенде: временного URL, режима редактора или внутреннего маршрута.
Не передавайте токен Drupal в браузер без понимания последствий. Если токен нужен для предпросмотра, ограничьте его область действия и срок жизни, а лучше выполняйте запрос через серверную часть фронтенда. Проверяйте также CORS: разрешённый origin, методы и заголовки должны соответствовать реальному клиенту, а не быть открытыми для всех доменов.
Для публичного сайта предпочтительна архитектура с одинаковым origin или серверным прокси. Она уменьшает количество проблем с CORS и позволяет не раскрывать внутренний адрес Drupal. Авторизация, refresh токенов и хранение секретов — отдельный контур безопасности, не часть обычного запроса списка статей.
Что ломается чаще всего
Фронтенд ожидает поле, которого нет
После изменения модели редактор может удалить поле, переименовать его или сделать необязательным. Клиент должен обрабатывать отсутствие изображения, автора и связанной сущности, а не обращаться к глубоко вложенному значению без проверки.
Список и карточка используют разные правила
Список фильтрует материалы по публикации, а страница статьи запрашивает материал напрямую по UUID. В результате ссылка существует, но страница показывает снятую с публикации запись. Правило видимости должно быть одинаковым для всех публичных маршрутов.
Запросы к связям превращаются в N+1
Если фронтенд получает список из 20 статей и отдельно загружает автора и изображение каждой, один экран создаёт десятки запросов. Используйте include, но следите за размером ответа и не включайте весь граф сущностей без необходимости.
Кеш скрывает исправление
После публикации редактор видит новую версию в Drupal, а посетитель — старую. Проверяйте ответ непосредственно с API, затем CDN и только после этого кеш приложения. У каждого слоя должны быть понятные заголовки и процедура очистки.
Когда headless Drupal лучше не выбирать
Если сайт состоит из простых страниц, не требует мобильного приложения и должен быстро запускаться силами небольшой команды, обычный Drupal с Twig может быть дешевле. Headless добавляет отдельную сборку, наблюдаемость, деплой фронтенда, контур авторизации и синхронизацию кешей.
Headless оправдан, когда один контент обслуживает несколько каналов, нужен независимый стек интерфейса или команда уже поддерживает React, Vue, Next.js либо другой клиентский слой. Считать нужно не только стоимость разработки, но и цену поддержки двух приложений.
Что делать дальше
Соберите небольшой вертикальный срез: один тип материала, одно изображение, список, детальная страница и снятие публикации. Для него измерьте размер JSON, время ответа без кеша и с кешем, количество запросов к связанным сущностям и время обновления страницы после публикации.
После этого зафиксируйте контракт API в репозитории, настройте мониторинг ошибок 4xx и 5xx, а затем отдельно протестируйте предпросмотр и очистку CDN. Инвалидацию кеша и SEO для headless-сайта стоит рассматривать как следующие самостоятельные задачи, а не прятать их в общий «настройте фронтенд».
Контент-конвейер: Из одной идеи — текст, изображение, озвучка и ролик. Один заказ вместо четырёх.
Спросить за 60 ₽Источники: JSON:API module — Drupal.org, JSON:API — Drupal.org
Частые вопросы
Какой стек фронтенда выбрать для Drupal headless?
Нужен ли GraphQL, если уже есть JSON:API?
Можно ли использовать эти приёмы в Drupal 9?
Что делать, если JSON:API возвращает 403?
Как сделать предпросмотр неопубликованной статьи?
Почему после публикации фронтенд показывает старую версию?
Можно ли отдавать все данные через один запрос с include?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.