Разбор от сообщества: TrueAPI Честного знака и API ЭДО Лайт в формате OpenAPI 3.0/
TrueAPI Честного знака и API ЭДО Лайт в формате OpenAPI 3.0 — два подхода к интеграции, способные упростить жизнь 1С-специалистам. Но за формальной красотой спецификаций скрываются ловушки, неочевидные на первый взгляд. Разбираем «под капотом»: где спецификация врёт, как не пропустить «синхронный» ответ и почему даже валидный по схеме JSON может упасть с HTTP 400.
Две спецификации — две философии: в чём подвох
На первый взгляд TrueAPI (Честный знак) и API ЭДО Лайт (Диадок) похожи: оба предоставляют машиночитаемые спецификации в формате OpenAPI 3.0. Однако подходы к описанию данных и обработке ошибок принципиально разные.
TrueAPI: строгая типизация и валидация на стороне сервера
Спецификация TrueAPI описывает каждый запрос с жёсткими схемами JSON Schema draft-07. Любое лишнее поле в теле запроса — и сервер возвращает 400 Bad Request с детальным сообщением. Проблема в том, что спецификация не всегда синхронизирована с реальным API. Например, в одном из методов маркировки появилось новое поле signature_date, которого нет в опубликованной схеме. При его отправке — ошибка. Но если поле обязательное, а его в схеме нет — как быть? Только экспериментальный подбор.
// Пример отправки запроса к TrueAPI с телом, сформированным по схеме
Процедура ОтправитьЗапросЧЗ(ТелоЗапроса)
HTTPСоединение = Новый HTTPСоединение("api.честныйзнак.рф", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL, Ложь);
HTTPЗапрос = Новый HTTPЗапрос("/api/v3/true-api/cises/create", Новый Соответствие);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json");
HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступа);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, "UTF-8");
Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 400 Тогда
ТелоОшибки = Ответ.ПолучитьТелоКакСтроку("UTF-8");
// Разбор ошибки
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТелоОшибки);
// ... обработка JSON ошибки
Чтение.Закрыть();
ИначеЕсли Ответ.КодСостояния = 200 Тогда
// Успех
КонецЕсли;
КонецПроцедуры
Не доверяйте слепо официальной схеме OpenAPI для TrueAPI. Реальная спецификация может отставать на 1-2 версии. Всегда тестируйте на тестовом контуре с включённым логированием тела запроса и ответа.
API ЭДО Лайт: упрощение через OpenAPI 3.0 с плавающими полями
API ЭДО Лайт от Диадока идёт другим путём: схемы намеренно ослаблены — многие поля разрешены, но не обязательны. Спецификация использует additionalProperties: true и нестрогие oneOf. Это удобно для быстрой интеграции, но ведёт к другой ловушке: вы можете отправить невалидные с точки зрения бизнес-логики данные, которые пройдут JSON-валидацию, но сервер ответит 422 Unprocessable Entity с человекочитаемой ошибкой. То есть спецификация не гарантирует корректность на уровне предметной области.
// Пример запроса к API ЭДО Лайт с неполным документом
Процедура ОтправитьДокументЭДО(СсылкаНаДокумент)
// Формируем JSON-тело вручную (упрощённо)
JsonТело = "{ ""Document"": { ""Type"": ""Invoice"", ""Content"": { ... } } }";
HTTPСоединение = Новый HTTPСоединение("api.edo.light.1c.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = Новый HTTPЗапрос("/v2/documents");
HTTPЗапрос.УстановитьТелоИзСтроки(JsonТело, "UTF-8");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json");
HTTPЗапрос.Заголовки.Вставить("Authorization", "Token " + Токен);
Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 422 Тогда
// Бизнес-ошибка: не хватает обязательных полей
ТекстОшибки = Ответ.ПолучитьТелоКакСтроку("UTF-8");
Сообщить("Бизнес-ошибка: " + ТекстОшибки);
КонецЕсли;
КонецПроцедуры
Ловушка №1: Псевдо-динамические параметры в спецификации OpenAPI
Обе спецификации используют OpenAPI 3.0, но при попытке сгенерировать клиентский код (через генераторы в 1С или сторонние утилиты) вы столкнётесь с проблемой: спецификация содержит параметры, которые выглядят как константы, но на деле зависят от предыдущего ответа. Например, в TrueAPI для получения статуса КМ требуется передавать requestId, который возвращается в ответе на создание. В схеме этот параметр описан как обычный строковый, но без контекста его не получить. А в ЭДО Лайт аналогично — documentId для подписания.
Генераторы кода (например, от 1С или OpenAPI Generator) этого не учитывают. Вы получите функцию с параметром requestId, но откуда его взять — не описано. Приходится вручную добавлять логику последовательных вызовов.
Как обойти: контекстный клиент
Создайте класс-обёртку, который хранит состояние последнего ответа и автоматически подставляет необходимые идентификаторы. Пример на псевдокоде (через реальный API 1С):
// Псевдокод: класс-контекст для TrueAPI (через HTTPСоединение)
// В реальности реализуется через внешние обработки или общие модули
Функция СоздатьКлиентЧЗ(Токен) Экспорт
Клиент = Новый Структура;
Клиент.Вставить("Токен", Токен);
Клиент.Вставить("ПоследнийRequestId", Неопределено);
Возврат Клиент;
КонецФункции
Процедура СоздатьКМ(Клиент, Товары) Экспорт
Запрос = Новый HTTPЗапрос("/api/v3/true-api/cises/create");
// ...
Ответ = ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку("UTF-8"));
// Парсим JSON
Чтение.Прочитать();
Чтение.Прочитать();
Клиент.ПоследнийRequestId = Чтение.ТекущееЗначение; // пример
Чтение.Закрыть();
КонецЕсли;
КонецПроцедуры
Процедура ПолучитьСтатусКМ(Клиент)
Если Клиент.ПоследнийRequestId = Неопределено Тогда
ВызватьИсключение "Сначала создайте запрос";
КонецЕсли;
// Используем requestId
HTTPЗапрос = Новый HTTPЗапрос("/api/v3/true-api/cises/status?id=" + Клиент.ПоследнийRequestId);
// ...
КонецПроцедуры
Ловушка №2: Асинхронность и тайм-ауты в TrueAPI Честного знака
TrueAPI использует асинхронный паттерн: отправка запроса возвращает 202 Accepted и идентификатор задачи. Реальный результат — 200 OK — приходит только через несколько секунд. Самая частая ошибка — ждать 200 сразу и при получении 202 считать вызов неудачным. В спецификации это описано, но в коде 1С часто забывают добавить цикл ожидания с задержкой.
Не используйте бесконечный цикл с ожиданием — вы рискуете заблокировать сеанс 1С на неопределённое время. Всегда устанавливайте таймаут (через свойство HTTPСоединение) и ограничение на количество попыток.
// Корректная обработка асинхронного ответа TrueAPI
Процедура ОтправитьИДождатьсяРезультата(ТелоЗапроса)
МаксПопыток = 10;
ЗадержкаСек = 2;
// Отправляем
HTTPСоединение = Новый HTTPСоединение(...);
Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния <> 202 Тогда
ВызватьИсключение "Ожидался 202";
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку("UTF-8"));
// ... получаем requestId
requestId = ПолучитьИдИзОтвета(Чтение);
Чтение.Закрыть();
// Ожидание результата
Для Попытка = 1 По МаксПопыток Цикл
Пока Пауза(ЗадержкаСек) Цикл КонецЦикла; // имитация задержки
HTTPЗапросСтатус = Новый HTTPЗапрос("/api/v3/.../status?id=" + requestId);
ОтветСтатус = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапросСтатус);
Если ОтветСтатус.КодСостояния = 200 Тогда
// Успех
Возврат;
ИначеЕсли ОтветСтатус.КодСостояния = 202 Тогда
// Ещё не готов
Продолжить;
Иначе
// Ошибка
ВызватьИсключение "Неожиданный статус: " + ОтветСтатус.КодСостояния;
КонецЕсли;
КонецЦикла;
ВызватьИсключение "Превышено время ожидания";
КонецПроцедуры
Что делать прямо сейчас: чек-лист для внедрения
- Проверьте актуальность спецификации. Скачайте схему OpenAPI из официального источника и вручную проверьте несколько эндпоинтов на тестовом контуре. Ищите поля, которые не описаны, но отправляются сервером (часто в ответах на ошибки).
- Настройте логирование тела запросов и ответов. Используйте
ЗаписьЖурналаРегистрациис телом JSON (обрезайте при больших размерах). Это спасёт при расследовании 400 и 422. -
Расширение «НОПик» для 1С — встраиваемый коннектор к внешнему AI с интеллектуальным поиском по базе. Задавайте вопросы обычными словами - AI сам найдёт нужное. 45 дней бесплатно.
Попробовать НОПик →