Как получить реквизиты строк табличной части через 1С REST OData и почему не работает $expand?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Рассмотрим частую проблему, с которой сталкиваются разработчики при интеграции с 1С через стандартный протокол OData. Допустим, мы получаем документ в формате JSON и видим, что для табличной части возвращаются только ссылки-идентификаторы (GUID), например, Номенклатура_Key. Нам же необходимо подтянуть строковое наименование, артикул и другие реквизиты связанных справочников. Попробуем разобраться, как правильно решить эту задачу.

Суть проблемы и ограничения стандартного OData

В начале проанализируем типичный подход. Разработчик делает GET-запрос к документу, например, к документу реализации товаров:


// Создать HTTP-запрос на основе URL.
АдресРесурса = "/*******/odata/standard.odata/Document_РеализацияТоваров(guid'" + UID + "')?$format=json";
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);

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


ТоварыНакладной = Док.Получить("Товары");
Если ТоварыНакладной.Количество() > 0 Тогда
    Для каждого Товар Из ТоварыНакладной Цикл
        нСтр = Товары.Добавить();
        // Здесь мы получаем только GUID, а нужно еще и наименование!
        нСтр.Номенклатура =  Товар.Получить("Номенклатура_Key");
        нСтр.Характеристика = Товар.Получить("Характеристика_Key");
        нСтр.Количество = Товар.Получить("Количество");
        нСтр.Цена = Товар.Получить("Цена"); 
    КонецЦикла;    
КонецЕсли;    

Логичным шагом кажется использование параметра $expand, который в OData предназначен для разворачивания связанных сущностей. Однако, стандартный REST-интерфейс 1С реализован на базе старого протокола OData версии 3. Согласно официальной документации 1С, на $expand наложены жесткие ограничения:

  1. Не поддерживается расширение реквизитов табличных частей.
  2. Не поддерживается расширение при запросе одиночных сущностей (например, конкретной строки табличной части).
  3. Заставить стандартный OData одним запросом отдать табличную часть вместе с подтянутыми из справочников наименованиями невозможно на уровне платформы.

Ошибочный подход: Запрос в цикле (проблема N+1)

Разберем самую опасную идею — делать отдельный OData-запрос для каждой строки табличной части. Если в документе 200 строк, скрипт отправит 200 GET-запросов к серверу 1С. Это классический антипаттерн «N+1 запрос».

Каждый HTTP-вызов к OData — это затраты времени на установку сетевого соединения, авторизацию, проверку прав, парсинг запроса веб-сервером и платформой. Если несколько пользователей одновременно откроют такие документы, мы получим тысячи запросов в секунду. Это гарантированно исчерпает пул сеансов платформы и «повесит» веб-сервер (IIS или Apache).

Рабочее решение 1: Пакетный запрос с использованием $filter и OR

Посмотрим на более жизнеспособный обходной путь. Мы можем собрать все уникальные GUID номенклатуры из полученной табличной части в один массив и отправить один дополнительный запрос к справочнику.

Поскольку 1С поддерживает только OData v3, удобный оператор IN (появившийся в OData v4) здесь не сработает. Нам придется реализовывать отбор списка через логическое сложение оператором OR. Фильтр будет выглядеть так:

$filter=Ref_Key eq guid'...' or Ref_Key eq guid'...' or Ref_Key eq guid'...'

Важные нюансы реализации этого подхода:

  1. Группировка запросов (чанкинг): Существует критическое ограничение веб-серверов на максимальную длину строки запроса URL (обычно 2048 или 8192 символа). Если объединить через OR сотни GUID, сервер вернет ошибку 414 URI Too Long.
  2. Порционная отправка: Разбиваем массив уникальных ссылок на порции (чанки) примерно по 30–40 штук и выполняем запросы к сущности Catalog_Номенклатура пакетами.
  3. Слияние данных: После получения ответов на эти несколько пакетных запросов, сопоставляем справочные данные со строками табличной части на стороне клиента.

Рабочее решение 2: Оптимальный подход (Собственный HTTP-сервис)

Рассмотрим самое правильное и архитектурно верное решение. Если стандартный интерфейс OData требует написания сложных "костылей" с чанками и склейкой данных на клиенте, от него лучше отказаться. Гораздо эффективнее разработать собственный HTTP-сервис прямо в конфигурации 1С (или в расширении).

Разберем по шагам, как это реализовать:

  1. В дереве метаданных добавляем объект HTTPСервис (например, с корневым URL myapi).
  2. Создаем шаблон URL, например /v1/documents/realization/{id} и добавляем метод для HTTP-глагола GET.
  3. В модуле метода пишем обычный 1С-запрос, который одним обращением к СУБД выбирает документ, его табличную часть и левым соединением подтягивает наименования справочника Номенклатура.
  4. Сериализуем результат выполнения запроса в JSON (через структуру и массив) с помощью объекта ЗаписьJSON и возвращаем ответ.

Пример логики запроса внутри HTTP-сервиса:


ТекстЗапроса = 
"ВЫБРАТЬ
|    РеализацияТоваровУслугТовары.Номенклатура.УникальныйИдентификатор() КАК Номенклатура_Key,
|    РеализацияТоваровУслугТовары.Номенклатура.Наименование КАК Номенклатура_Desc,
|    РеализацияТоваровУслугТовары.Количество КАК Количество,
|    РеализацияТоваровУслугТовары.Цена КАК Цена
|ИЗ
|    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
|    РеализацияТоваровУслугТовары.Ссылка = &СсылкаНаДокумент";

Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("СсылкаНаДокумент", ИскомаяСсылка);
Результат = Запрос.Выполнить().Выгрузить();
// Далее формируем массив структур и записываем в JSON

Преимущества такого подхода:

В заключение, если вам нужно получать сложные, вложенные структуры данных с развернутыми реквизитами из 1С, всегда делайте выбор в пользу разработки собственных HTTP-сервисов, оставляя стандартный интерфейс OData для простых задач (выгрузки плоских списков и CRUD-операций одиночных справочников).

← На главную