При разработке веб-сервисов и HTTP-сервисов в расширениях конфигурации разработчики часто сталкиваются с необходимостью выгрузки данных в формат JSON. Если структуры данных содержат сложные типы (например, таблицы значений, ссылки на справочники, документы или неопределенные значения), встроенный метод 1С ЗаписатьJSON требует указания обработчика сложного типа — экспортной функции в параметре ИмяФункцииПреобразования и соответствующего модуля в параметре МодульПреобразования.
Однако в контексте веб-сервиса расширения возникают архитектурные ограничения платформы 1С. Разберем подробнее, почему возникает эта проблема и какими способами ее можно решить.
Выясним главные причины, по которым штатный вызов функции преобразования вызывает ошибку:
МодульПреобразования платформа разрешает передавать только ограниченный список объектов: ОбщийМодуль, ОбработкаОбъект, ОтчетОбъект или УправляемаяФорма. Модуль Web-сервиса не относится к объектным типам и не может быть передан в этот параметр.ЭтотОбъект: В коде веб-сервиса переменная ЭтотОбъект не определена, так как модуль исполняется вне объектного контекста.Проанализируем практические варианты обхода данного ограничения.
Наиболее простое и надежное решение — отказаться от использования параметра ИмяФункцииПреобразования и подготовить структуру данных заранее перед вызовом сериализатора. Для этого все сложные типы приводятся к базовым типам 1С (массивы, структуры, строки, числа, булево).
Рассмотрим пример обхода таблицы значений и приведения ссылок к строковому представлению:
Функция ПреобразоватьТаблицуВМассив(ТаблицаЗначений)
МассивРезультат = Новый Массив;
Для Каждого Стр Из ТаблицаЗначений Цикл
ЭлементСтруктура = Новый Структура;
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Значение = Стр[Колонка.Имя];
// Обработка ссылочных типов и сложных значений
Если ЗначениеЗаполнено(Значение) Тогда
Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
ЭлементСтруктура.Вставить(Колонка.Имя, Строка(Значение));
ИначеЕсли Справочники.ТипВсехСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
ЭлементСтруктура.Вставить(Колонка.Имя, Строка(Значение));
Иначе
ЭлементСтруктура.Вставить(Колонка.Имя, Значение);
КонецЕсли;
Иначе
ЭлементСтруктура.Вставить(Колонка.Имя, "");
КонецЕсли;
КонецЦикла;
МассивРезультат.Добавить(ЭлементСтруктура);
КонецЦикла;
Возвращать МассивРезультат;
КонецФункции
После такой подготовки вызов метода ЗаписатьJSON выполняется без указания модуля преобразования:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПодготовленныйМассив);
СтрокаJSON = ЗаписьJSON.Закрыть();
Тип ВнешняяОбработкаОбъект является допустимым значением для параметра МодульПреобразования. Мы можем хранить файл внешней обработки в макете расширения (как двоичные данные) или во временном каталоге, подключать его в коде сервиса и передавать экземпляр обработки в метод ЗаписатьJSON.
Разберем пример реализации по шагам:
ОбработкаСложныхТипов(Свойства, Отказ).
ИмяФайла = ПолучитьИмяВременногоФайла("epf");
ДвоичныеДанные = ПолучитьМакет("ВнешняяОбработкаПреобразованияJSON");
ДвоичныеДанные.Записать(ИмяФайла);
ОбработкаОбъект = ВнешниеОбработки.Создать(ИмяФайла);
ЗаписатьJSON(ЗаписьJSON, МассивJSON, , "ОбработкаСложныхТипов", ОбработкаОбъект);
УдалитьФайлы(ИмяФайла);
Если в основной конфигурации уже есть серверный общий модуль с универсальными функциями преобразования (например, модули БСП ОбщегоНазначенияКлиентСервер или модули работы с JSON), расширение может свободно использовать их имя в качестве параметра МодульПреобразования.
Посмотрим на пример передачи имени существующего модуля:
ЗаписатьJSON(ЗаписьJSON, Данные, , "ОбработкаСложныхТипов", ОбщийМодульИмя);
Если приемник JSON готов принимать данные в формате XDTO 1С, вместо ручного обхода и вызова ЗаписатьJSON можно воспользоваться вызовом СериализаторXDTO. Он умеет автоматически раскладывать ссылочные типы, таблицы значений и наборы записей без необходимости передавать модуль преобразования:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ДанныеОбъект, НазначениеТипаXML.Явное);
СтрокаJSON = ЗаписьJSON.Закрыть();
Важно: Данный способ формирует специфическую структуру JSON с тегами типов 1С, поэтому его стоит применять в случаях, когда на принимающей стороне также используется платформа 1С или имеется парсер формата 1С XDTO.