Практика доступа в базу 1С через протокол oData. Изменение данных

Программирование - Практика программирования

Продолжаем знакомство с протоколом oData и в данной статье мы рассмотрим такие вопросы, как минимально необходимый багаж теоретических знаний, необходимый для работы, способы изменения доступных данных, а также с какими ограничениями можем при этом столкнуться. Осторожно, будет много скриншотов!

Эта работа является естественным продолжением моей предыдущей статьи "Практика доступа в базу 1С через протокол oData. Чтение данных" и все операции будут выполняться в той же демо-базе "Управление торговлей (базовая), редакция 10.3", к которой я предоставил доступ по OData в предыдущей статье.

 

Что нам нужно знать про HTTP?

OData - это протокол работы с данными поверх классического протокола HTTP. Это означает, что у каждого элемента данных есть свой URL, а чтобы сообщить серверу, что именно вам необходимо с этим элементом сделать (просто получить или изменить), используются HTTP-методы. Для многих эти сущности возможно будут новинкой. Ведь знание о HTTP-методах совершенно не нужно пользователям при их обычном интернет-серфинге (где тотально применяется GET). И даже веб-разработчики зачастую в курсе только про пару GET и POST, которые считают методами для отправки на сервер данных из форм.

Протокол OData подразумевает применение следующих пяти методов для работы с данными:

  • GET - самый популярный из методов, который предназначен для запроса данных на чтение по указанному адресу;
  • POST - метод для создания нового элемента данных, в качестве адреса обычно указывают только класс объектов;
  • PUT - метод для замены свойств элемента данных на сервере по указанному полному адресу теми свойствами, которые передаются вместе с этим запросом. Обычно в популярных реализациях этого метода передача неполного состава свойств приводит к ошибке; так же часто адресация несуществующего элемента данных приводит к его автоматическому созданию (как это было реализовано в платформе 1С посмотрим ниже);
  • PATCH - метод для обновления только переданных свойств элементов данных;
  • DELETE - метод предназначенный для удаления элементов данных.

 

Клиент для протокола OData

Для "общения" с базой 1С по протоколу OData нам понадобится некоторый инструмент. И поскольку нас интересует уже не банальный GET, а полный спектр HTTP-методов, то обычные браузеры и подавляющее большинство популярных программ с поддержкой OData нам не подойдут. Потребуется что-то более функциональное.

Есть несколько распространенных вариантов. Опытные веб-разработчики, хорошо знакомые с сетевыми технологиями, на этих словах уже запускают свой любимый Fiddler, в котором на закладке Composer можно эмулировать любой из HTTP-методов, а потом, переключившись на закладку Inspectors, посмотреть полученный от сервера ответ. А поклонники UNIX-way, даже работая на Windows, конечно же имеют в наличии старый добрый автомат Калашникова консольный cUrl, в котором с помощью ключа -X можно указать требуемый HTTP-метод.

Но, поскольку мы тут все программисты 1С, то почему бы не написать собственный "велосипед"? Тем более что это очень просто и код можно в будущем использовать в других работах. Для этого поместим на форму новой обработки поля для подключения, авторизации, передачи параметров и вывода ответа сервера, а в обработчик на нажатие кнопки разместим примерно такой код:

	Соединение = Новый HTTPСоединение(Сервер, Порт, Логин, Пароль,,,?(СоединениеЗащищено, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено));
	ЗапросСервера = Новый HTTPЗапрос(ПутьНаСервере);
	ЗапросСервера.УстановитьТелоИзСтроки(ТелоЗапроса);
	ОтветСервера = Соединение.ВызватьHTTPМетод(Метод, ЗапросСервера);
	ТелоОтвета = ОтветСервера.ПолучитьТелоКакСтроку();
	ЗаголовкиОтвета = "Status Code: " + ОтветСервера.КодСостояния + Символы.ПС;
	Для каждого ЗначениеЗаголовка Из ОтветСервера.Заголовки Цикл
		ЗаголовкиОтвета = ЗаголовкиОтвета + Символы.ПС +
			ЗначениеЗаголовка.Ключ + " : " + ЗначениеЗаголовка.Значение;
	КонецЦикла; 

Если захотите ознакомится с моей обработкой во вложении, то там будет дополнительно разбор переданного URL с определением протокола (HTTP или HTTPS), вычисление порта и отбрасыванием из адреса прочую вспомогательную информацию. Выглядит примерно так:

Обработка по работе с HTTP-методами

Ломать - не строить

Для начала возьмем самую простую операцию - удаление, на примере контрагента "АОЗТ Лабан" из демо базы УТ10.3. Собственно повторяем вызов строчки из выше опубликованного скриншота, но вместо метода GET воспользуемся методом DELETE. Теперь вместо ответа 200 (все хорошо), сервер нам отвечает 204 (нет содержимого) - это нормальное поведение именно для удаления.

удаление ресурсаДавайте перейдем в саму базу 1С и по журналу регистрации проверим, что же произошло:

журнал с удалениями

Как мы видим, наш контрагент был успешно удален вместе со всеми своими подчиненными связанными данными. Тот факт, что для всех  этих справочников в роли моего пользователя было запрещено интерактивное удаление, не имеет значения. Удаление по протоколу OData приравнивается к удалению из программного кода. Но, как видим, есть и различие - при программном удалении контрагента его подчиненные элементы остались бы в базе. Это важно и потому запоминаем: если у хоть одной роли пользователя есть право "Удаление", то у вас есть риск на безвозвратную потерю множества данных без контроля на наличие ссылок:

побитые данные

Кстати, повторная попытка удалить элемент с помощью метода DELETE аналогично запросу с помощью GET приведет к ошибке 404 (не найдено):

запрос удаленного

 

Создаем новое (или старое)

Как жаль, что контрагента "АОЗТ Лабан" постигла такая печальная участь... А можем ли мы его спасти без восстановления базы из бэкапа или без выполнения кода непосредственно в УТ?

Начну с цитаты из документации:

Для создания объекта следует воспользоваться POST-запросом с использованием URL набора сущностей, передав в теле запроса документ (в поддерживаемом формате), который содержит значения полей создаваемого объекта. Если передаваемый документ содержит свойства, отсутствующие у создаваемого объекта, то эти свойства игнорируются.

Больше ничего у нас с вами нет. Ни перечня обязательных полей. Ни перечня исключаемых полей. Ни упоминания о возможности создания объекта с нужным нам значением GUID. Поэтому начинаем свободные эксперименты!

Еще с самого первого запроса GET у меня осталось описание контрагента, со свойством Ref_Key, в котором находился его GUID (даже если бы его у меня не было, то я мог получить его из документа, который все еще ссылается на удаленного контрагента). Сначала попробуем отдать полностью это описание на URL с указанием элемента. Ожидаемо получаем ошибку 404 как и в случае методов GET и DELETE (см. выше). Теперь обращаемся к "набору сущностей", как того требует документация:
http://localhost/DemoTrdBase/odata/standard.odata/Catalog_Контрагенты?$format=json

И на этот раз у нас все получилось:

запрос на созданиесоздание в журнале

Более того, все получилось именно так как и было задумано - новый элемент был создан именно с тем GUID (а следовательно с той же ссылкой) как и ранее удаленный! Это хорошо видно на документе закупки ТК000000030 от 13.03.2007, где контрагент появился, но его договора и типа цен по прежнему нет (их можно аналогично восстановить, воспользовавшись в качестве образца для структуры подчиненные данные похожего контрагента, лишь в качестве GUID подставив правильные строки):

исправленный документ

Это все превосходно, но а если у объекта множество свойств и они нам сейчас не интересны (пусть будут значения по умолчанию). Можем ли мы уменьшить размер передаваемого пакета и следовательно увеличить скорость гипотетического создания множества объектов в цикле? Для ответа на этот вопрос пойдем по пути экстремальной минимизации - попробуем создать элемент не указав ему вообще ни единого свойства!

создание пустогопустой контрагентОтлично, выходит, что нам нет нужды перечислять все значения по-умолчанию и платформа за нас все сделает сама. Но справочник - это слишком просто. Интереснее попробовать с документом, при записи которого, как мы знаем, обычно возникает ошибка платформы, если не указать дату. Попробуем на примере упомянутой выше приходной накладной:

Не то чего я ожидал, но тем не менее отличный результат! Следовательно все программно-обрабатываемые события объектов не игнорируются! Это вам не тупой прямой insert в СУБД, а процедура записи полностью идентичная программной записи из какой-нибудь обработки. Но все же, что же будет с датой? Для этого нам нужен более простой документ, который крепко не привязан к рабочим процессам в УТ, к примеру Событие:

создание события без даты

Да, ошибка получена. Теперь лично у меня к механизму создания элементов методом POST вопросов больше не осталось. Все оказалось довольно простым и без "заморочек": можно устанавливать уникальный идентификатор новым ссылкам, отсутствуют какие-либо требования к обязательным или запрещенным свойствам в описании, лишние (не относящиеся к объекту) свойства просто игнорируются, запись в базу следует всем тем же правилам, что и обычная программная запись.

 

Теперь будем изменять (в хорошем смысле)

Как я уже упомянул выше, для изменения данных в базе 1С посредством OData можно использовать методы PUT и PATCH.

Давайте сразу же попробуем применить PUT в созидательной роли POST. К сожалению, тут ничего интересного мы не узнаем. В контексте коллекции мы получаем ошибку, что данный метод недопустим, а при указании произвольного GUID мы получим ошибку, что изменяемый экземпляр не найден:

обновление несуществующегосоздание обновлением

А что если не указывать все реквизиты? Действительно, практика показала, что можно не указывать все реквизиты объекта и эти свойства станут заполняться значениями по умолчанию, что иногда может быть удобным. Ниже пример, где у справочника были затерты введенные вручную полное наименование и параметры прописи для валюты:

затирание свойств при обновленииВот и все интересное, что мы могли узнать про PUT, и потому переходим к более гибкому методу PATCH. При работе с этим методом, в отличии от его предшественника, нам для установки значения единичного реквизита больше не нужно делать предварительный GET для запроса значений всех свойств, что бы потом эти же свойства не затереть значениями по-умолчанию. Нам достаточно лишь идентификатора объекта и нового значения указанного свойства:

изменение свойстваТеоретически, данный метод мог бы быть очень удобным для быстрого массового изменения элементов с помощью единого вызова. На пример, чтобы сменить основного менеджера для всех поставщиков, пометить на удаление документы без суммы и так далее. К сожалению, компания 1С не дала нам такую интересную возможность; для массового изменения нам доступна лишь только серия вызовов в цикле:

попытка массового изменения

 

Итог

Не смотря на отсутствие некоторых удобств, протокол OData на платформе "1С:Предприятие 8" позволил нам совершать все базовые операции над данными. Таким образом, имея доступ в базу только по этому протоколу, можно реализовать полноценную интеграцию с некоторой внешней системой.

Статья вышла длинной не смотря на то, что были рассмотрены самые простые операции. Часть возможных интересных экспериментов была оставлена за кадром, но вы можете самостоятельно попрактиковаться. К примеру, как на счет записать набор записей по какому-нибудь из регистров? ;)

Скачать файлы

Наименование Файл Версия Размер
Обработка для выполнения HTTP-методов
.epf 7,69Kb
25.12.17
10
.epf 7,69Kb 10 Скачать

См. также

Комментарии
1. Дмитрий Быков (Adam12345678) 3 02.01.18 05:50 Сейчас в теме
Интересная статья, спасибо.
2. DenisCh Гейтс (DenisCh) 02.01.18 06:58 Сейчас в теме
Соглашусь. Интересно.
baracuda; +1 Ответить
3. Maksim Panfilov (McSim_) 02.01.18 12:06 Сейчас в теме
"На самом интересном месте!.." :)
Как раз запросы к регистрам - самое интересное. Например, как получить сальдо на выбранном счёте на выбранную дату? Об этом информации в сети минимум.
5. Дмитрий Кинаш (Dementor) 241 02.01.18 19:36 Сейчас в теме
(3) в третьей части как раз хотел поиграться с виртуальными таблицами, блокировками, режимом загрузки и прочими "функциями".
4. Олег Дмитров (baracuda) 3 02.01.18 12:29 Сейчас в теме
6. Владимир Литвиненко (VladimirL) 593 09.01.18 13:14 Сейчас в теме
В записи данных в 1С через OData, есть большая опасность, которая может дать сильного пинка архитектору системы при активном использовании. В GRASP есть фундаментальный шаблон Information Expert, более известный под общим названием "инкапсуляция". Его нарушение ведет к детским болезням программирования, последствия же для системы в целом могу оказаться совсем не детскими.

Если обращение на запись через OData выполняет более чем одна внешняя система, то даже изменение типа реквизита может превратиться в настоящую эпопею с подключением всех разработчиков всех этих внешних систем. Не говоря уже о скованности по рукам и ногам при изменении алгоритмов записи/проведения внутри системы принимающей данные. Заканчивается это либо тем, что на развитие системы построенной на OData "забивают", ввиду сложности изменений и необходимости постоянно координировать взаимодействие множества разработчиков, либо развитие продолжается, но титаническими неоправданными усилиями. Ну или еще один путь - переписать все с применением более подходящих технологий ))

Конечно это не в целом к технологии OData и REST относится. Просто в 1С подход так реализован, что сложно для OData красивый интерфейс сделать, с возможностями хоть как-то напоминающими web-сервисы или хотя бы http-сервисы. Единственный интерфейс - этот тот что предлагает платформа без возможности его изменения, при этом он больше напоминает прямую запись в SQL .... в каждую таблицу отдельно.... без транзакций )) Ибо оптимистические блокировки не сильно помогают в борьбе за целостность данных.

Для 1С сейчас OData хорош только в универсальных алгоритмах, где изменение типа реквизита, появление обязательного к заполнению реквизита или изменение алгоритма обработки входящих данных не ведет к катастрофам. Для этого в алгоритмах отправки данных надо анализировать данные /odata/standard.odata/$metadata. Но многие ли так делают? Из известных публикаций только Metadata.js вспоминается.

Пока что имхо OData в 1С лучше применять на чтение. И в тех случаях, когда временный сбой в чтении данных не скажется сильно на работе всей системы.
Adam12345678; +1 Ответить
7. Дмитрий Кинаш (Dementor) 241 09.01.18 22:15 Сейчас в теме
(6) Спасибо за комментарий. Если его перевести на обычный язык, то вы хотели написать, что 1) при одновременной работе с интерфейсом нескольких клиентов возможны проблемы логической целостности; 2) при изменении метаданных базы 1С возникают проблемы в скриптах доступа. Ничего не пропустил?
9. Владимир Литвиненко (VladimirL) 593 10.01.18 13:44 Сейчас в теме
(7) Примерно так. По первому пункту проблема скорее даже не с количеством клиентов, а с тем, разные группы разработчиков отвечают за эти системы или это одна и та же команда. Скоординировать изменения кода в разнородных системах только потому, что произошли простейшие изменения в структуре объекта метаданных - сложная задача. При наличии же нормального интерфейса вроде web-сервиса или хотя бы http-сервиса рефакторинг или изменение логики происходит значительно проще.

По этим признакам реализация OData от 1С больше похожа на COM-подключение. Из плюсов - протокол http и кросплатформенность. Но ограничений еще больше: экспортные методы, целостность и согласованность данных, проверки при записи и т.д. Также нет объектной обертки к OData. Для взаимодействия между системами на 1С приходится писать обертки самостоятельно, чтобы в коде не было "простыни". Это облегчает ряд задач, но поскольку обертку можно применять только для алгоритмов отправки (на стороне клиента), то от главных проблем это увы не спасает.

Претензия разумеется не к публикации - плюсанул и буду ждать третью часть. Но хотел подчеркнуть эти ограничения, чтобы коллеги на грабли не наступали.
Adam12345678; +1 Ответить
8. Анатолий Фокин (Dos_1985) 10.01.18 05:49 Сейчас в теме
10. Игорь Пашутин (Alien_job) 137 16.01.18 14:34 Сейчас в теме
Спасибо за статью. Про ошибку при записи документа прокомментируете? У вас не написано что получилось изменить существующий в базе документ
11. Дмитрий Кинаш (Dementor) 241 16.01.18 18:50 Сейчас в теме
(10)
У вас не написано что получилось изменить существующий в базе документ

С помощью POST это действительно невозможно. И это хорошо - должен же быть хоть какой-то порядок :) С методами PUT и PATCH нет никаких проблем по изменению существующих документов, если известен их идентификатор - в моих примерах документы были успешно модифицированы.
12. Игорь Пашутин (Alien_job) 137 16.01.18 20:52 Сейчас в теме
(11) Ок, перепробую. Подскажете платформу на которой вы работаете?
13. Дмитрий Кинаш (Dementor) 241 17.01.18 00:50 Сейчас в теме
(12) сейчас установлена 8.3.11.2867. На ней же сделаны примеры из статьи.
Оставьте свое сообщение