Перейти к содержимому

Реестр источников

Реестр отвечает на два вопроса автора блока: какие данные вообще бывают и кто их поставляет. Это локальная копия каталога, который ведёт витрина; в PageCraft записи не создаются и не редактируются — они приходят синхронизацией.

Сущность Идентификатор Что описывает
Тип результата product_list форму данных: что такое «список товаров»
Источник catalog.products конкретного поставщика этих данных и его параметры

Один тип результата — много источников. Товары рубрики, избранное и результаты поиска возвращают одинаково устроенный product_list, поэтому один шаблон блока работает со всеми тремя. Ровно это и позволяет перечислять их в allowedSources одного слота: все источники слота обязаны иметь один result_type_id.

Поле Что
id строковый идентификатор; его кладут в allowedSources и default
result_type_id какой тип результата источник отдаёт
title, description человекочитаемые название и описание (могут отсутствовать)
params_schema JSON Schema объекта params привязки
context окружения, из которых источник берёт данные; пусто — работает везде
synced_at когда запись последний раз обновлялась из реестра

Непустой context означает контекстный источник: он отдаёт данные той сущности, которую сейчас показывают, и годится только для документа, чей вид даёт такое окружение. В allowedSources такие источники не перечисляются.

Поле Что
id строковый идентификатор, он же resultType слота
schema_json JSON-схема структуры данных, которые придут в data.<слот>
stub пример данных той же формы — на нём рисуется предпросмотр
synced_at дата синхронизации
  1. Понять, какие данные нужны блоку, и найти подходящий тип результата (GET /api/v1/data-result-types).
  2. Посмотреть его schema_json и stub — по ним пишется шаблон.
  3. Выбрать источники с этим result_type_id (GET /api/v1/data-sources) и положить подходящие по смыслу с пустым context в allowedSources. Источники с непустым context пропустить: их редактор предложит сам на подходящем документе.
  4. Открыть params_schema выбранных источников — оттуда берутся имена и типы параметров привязки.
Окно терминала
curl -H "Authorization: Bearer pb_..." \
'https://page-craft.4partners.io/api/v1/data-sources?limit=50&offset=0'
{
"data": [
{
"id": "catalog.products",
"result_type_id": "product_list",
"title": "Товары рубрики",
"description": "Список товаров выбранной рубрики",
"params_schema": {
"type": "object",
"properties": {
"rubric_id": { "type": "integer", "title": "Рубрика" },
"limit": { "type": "integer", "title": "Сколько показать", "default": 8 },
"sort": { "type": "string", "enum": ["popular", "new", "price"] }
}
},
"synced_at": "2026-05-19T12:00:00+00:00"
}
],
"total": 12,
"limit": 50,
"offset": 0
}

Человеческие названия берутся из самого реестра стандартными полями JSON Schema: title и description у источника и у каждого параметра в params_schema. Варианты enum подписываются расширением x-enumTitles — параллельным массивом строк того же порядка:

{
"sort": {
"type": "string",
"title": "Сортировка",
"enum": ["popular", "new", "price"],
"x-enumTitles": ["Популярные", "Новинки", "По цене"]
}
}

Поля необязательные: без них интерфейс покажет технический ключ. Значениями всегда остаются технические ключи, поэтому подписи ни на что, кроме отображения, не влияют. У типа результата верхнего уровня подписей в протоколе нет вообще — виден только идентификатор.

Повторяющиеся структуры (цена, изображение) выносятся в отдельный тип результата и переиспользуются по ссылке:

  • в schema_json{"$ref": "#/resultTypes/price_dto"};
  • в stub — парный маркер {"$stub": "#/resultTypes/price_dto"}.
{
"items": [
{
"name": "Кофеварка",
"variation": {
"price": { "$stub": "#/resultTypes/price_dto" },
"oldPrice": { "$stub": "#/resultTypes/price_dto" }
}
}
]
}

После разворачивания price превращается в данные типа price_dto{ "amount": 2990, "currency": "RUB", "formatted": "2 990 ₽" }.

Разворачивает ссылки клиент: редактор догружает недостающие типы рекурсивно и использует их для подсказок data.* и для предпросмотра. API отдаёт схемы как есть, поэтому при работе через REST ссылки нужно разрешать самостоятельно. Граничные случаи безопасны: $ref на несуществующий тип просто не даёт подсказок, $stub на тип без заглушки подставляет null, цикл обрывается.

Метод и путь Назначение
GET /api/v1/data-sources список источников, limit (1–200, по умолчанию 50) и offset
GET /api/v1/data-sources/{id} один источник целиком
GET /api/v1/data-result-types список типов результата с той же пагинацией
GET /api/v1/data-result-types/{id} тип результата со schema_json и stub

Списки обёрнуты в { data, total, limit, offset }, детальные ответы — в { source: … } и { result_type: … }. Аутентификация — API-ключ в заголовке Authorization: Bearer pb_….

Реестр наполняется синхронизацией с витриной: администратор PageCraft запускает её вручную (расписания и вебхуков нет). Записи опознаются по строковому идентификатору, поэтому повторная синхронизация обновляет существующую запись, а не плодит копии.

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

Истории изменений реестр не хранит: узнать, что у типа результата поменялась схема, можно только сравнив её с тем, на что рассчитывал шаблон блока.


Источники: backend/src/Controller/V1/DataSource/, backend/src/Controller/V1/DataResultType/, backend/src/Entity/DataSource.php, backend/src/Entity/DataResultType.php, backend/src/Service/SourcesSyncService.php, backend/src/Service/BlockSchemaValidator.php, front/src/lib/liquidAnalyze.ts (collectRefs, resolveStub), front/src/components/PageEditor/BindingSlotForm.tsx.