DATAREON Platform: двухуровневая валидация JSON в REST-запросах

· ·

DATAREON Platform: двухуровневая валидация JSON в REST-запросах

PrimeCoder · 2026 · формат: tech

Разбор новинки простыми словами: что это, кому нужно и брать ли.

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

Связанные услуги: каталог, AI Boost Team, стать клиентом.

DATAREON Platform: двухуровневая валидация JSON в REST-запросах — иллюстрация

Что вышло

Инженер сопровождения СОФРОС Илья Вязников выложил на Хабре практический разбор: как в DATAREON Platform настроить проверку JSON, который приходит в REST-запросе. Материал технический, среднего уровня, на 12 минут чтения, все примеры прогнаны на стенде платформы версии 3.2.

Тема выглядит как заметка для разработчика интеграций. На деле она про деньги. Каждый раз, когда склад передаёт в учётку партию товара и получает обратно «ошибка 400», кто-то садится сверять поля вручную. Час работы бухгалтера, полдня простоя документа, нервы руководителя. Всё это стоит ровно на той строчке, где написано, какого типа должно быть поле created_at.

Разбор интересен не описанием платформы, а найденной особенностью. DATAREON Platform умеет отклонять запрос до того, как запустится ваш собственный код проверки. Значит ошибки приходят к отправителю двумя разными заходами. Это меняет то, как вы проектируете ответ API и что обещаете партнёру в документации.

Сценарий, знакомый каждому интегратору

Складская система принимает новую партию и отправляет в платформу пакет о регистрации товара. Дальше данные уходят в учётную систему. В meta лежат сведения об источнике и документе, в массиве items — товарные позиции с названием, кодом, ценой и количеством.

Требования к данным в примере такие:

  • meta.source — строка, обязательна;
  • meta.document_type — строка, обязательна;
  • meta.created_at — дата и время, обязательна, не из будущего;
  • items — массив, минимум одна позиция;
  • items[].name — строка, обязательна;
  • items[].code — строка строго из пяти символов вида A-001: латинская буква A–Z, дефис, три цифры (шаблон ^[A-Z]-\d{3}$);
  • items[].price — десятичное число больше нуля;
  • items[].quantity — целое число больше нуля.

Задача прикладная: если что-то не так, склад должен узнать об этом сразу, а не от сотрудника учёта через неделю, когда документ уже разошёлся по отчётам.

Уровень первый: типы данных

Самая дешёвая линия защиты — объявить поля настоящими типами: String, DateTime, Decimal, Int. В платформе создаётся тип данных с двумя группами полей, и после этого она сама отклоняет значения не того типа.

Что это даёт на практике. В коде веб-обработчика created_at приходит уже как DateTime, price — как decimal, quantity — как int. Никаких DateTime.TryParse и int.TryParse. Сравниваете даты и числа напрямую, а не разбираете строки, надеясь, что отправитель не пришлёт европейский формат с точками.

Если объявить те же поля строками, платформа примет в них что угодно. И вся проверка формата ляжет на ваш обработчик — для каждого поля отдельно, с обработкой исключений и дефолтов. Разница по трудозатратам примерно как между «включить схему» и «написать свою схему».

Главная ловушка первого уровня

Типизация не заменяет проверку обязательности. И вот почему.

Поле, которое в JSON просто не передали, платформа ошибкой типа не считает. Она молча подставляет значение по умолчанию.

  • String → пустая строка, не null;
  • DateTime → 01.01.1900 00:00:00 (минимальный год из настроек поля);
  • Decimal и Int → 0;
  • Массив → пустой список.
Если поле в JSON просто не передано, платформа не считает это ошибкой типа и подставляет значение по умолчанию.

Явный null в не-nullable поле платформа отклоняет сама. А вот отсутствие поля — пропускает дальше, в ваш код.

Отсюда практический вывод, который стоит проговорить с командой один раз: форма проверки на обязательность меняется. Вместо «строка пустая?» вы проверяете «дата не равна 1900 году?» и «количество больше нуля?». Это неочевидно, и именно здесь появляются баги вида «товар без даты прошёл как валидный и упал на стороне учётной системы».

Вердикт: дефолты — удобная штука для необязательных полей и мина для обязательных. Отдельная проверка на 1900 год должна стоять в каждом обработчике, где дата обязательна. Это мусорное значение не должно уехать в целевую систему.

Уровень второй: бизнес-правила в коде

Всё, что типом не выразить, проверяется в веб-обработчике. Формат кода товара, диапазоны цены и количества, дата не из будущего, минимум одна позиция в массиве.

Когда проверка не прошла, обработчик выбрасывает ValidateParametersException и передаёт список проблемных полей. Клиент получает ответ вида:

{ "errorCode": 400, "errorMessage": "данные не прошли проверку", "notValidFields": "meta.created_at,items[0].code" }

Корректное сообщение получает HTTP 200 и уходит в платформу на дальнейшую обработку. Никакой самодеятельности с кодами ответа.

Единый формат ошибки: responseErrorSettings

Чтобы оба уровня отвечали одинаково, нужна внешняя система типа «Расширенный REST API». Именно в её конфигурации задаётся блок responseErrorSettings. По умолчанию его там нет — переключаетесь в режим редактора конфигурации и добавляете руками.

В блоке два ключевых параметра. validationErrorCode — HTTP-код, который получит клиент при ошибке валидации, в примере 400. bodyJsonTemplate — шаблон тела ответа. Это строка с экранированным JSON, а не вложенный объект, и в неё подставляются плейсхолдеры {errorCode}, {errorMessage} и {notValidFields}. Набор плейсхолдеров и имена ключей можно менять под свой контракт.

Текст ошибки и список полей в настройках не задаются. Их заполняет тот, кто ошибку обнаружил: платформа или ваш код.

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

  • нарушены типы или не передан обязательный параметр — ошибку формирует платформа, до запуска кода обработчика;
  • обработчик выбросил ValidateParametersException;
  • в ответе обработчика с флагом «Ожидание ответа» пришёл ResponseCode из диапазона 400–500;
  • возник WebServiceException, то есть внутренняя ошибка платформы.

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

Подвох, ради которого стоило писать разбор

Два уровня проверки означают две последовательные итерации. Сначала отправитель исправляет типы данных. И только потом узнаёт о нарушениях бизнес-правил.

При тестировании кейса выяснилась интересная особенность: DATAREON Platform может отклонить запрос ещё до выполнения пользовательского кода валидации.

Формат ответа единый, а список проблемных полей — нет. В одном ответе клиент видит только ошибки типов, во втором — только бизнес-правила. Если в пакете из 200 позиций три битых типа и сорок неверных кодов, разработчик на стороне склада получит три поля, починит их, отправит снова и только тогда увидит сорок.

Что с этим делать. Вариантов три, и выбирать придётся осознанно.

  1. Принять как есть и написать в документации. Самый дешёвый путь. В контракте API честно фиксируете: ошибки валидации возвращаются итеративно, сначала по типам, затем по правилам. Клиентская сторона проектирует повторные отправки с лимитом попыток.
  2. Ослабить типы и валидировать всё в коде. Объявляете поля строками, собираете полный список проблем за один проход. Взамен теряете автоматическую типизацию и пишете разбор каждого поля руками — со всеми TryParse, которые платформа делала за вас.
  3. Разделить уровни по смыслу. Типами закрываете то, что физически не может быть исправлено на стороне отправителя без переделки его модели данных: даты, числа, массивы. Бизнес-правила, которые отправитель может проверить у себя заранее (справочник кодов товара, диапазоны), вы отдаёте партнёру в виде спецификации. Тогда вторая итерация становится редкой.

Третий путь самый взрослый. Он требует, чтобы кто-то один отвечал за контракт API и держал справочники синхронными. Зато количество повторных отправок падает без потери автоматических проверок.

Кому это нужно и как применить

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

Порядок действий для собственника или руководителя интеграций, который не пишет код, но принимает решения:

  1. Проверьте, что у вас в конфигурации внешней системы включён responseErrorSettings. Если блока нет, ваши клиенты получают ошибки в разнобой — это первое, что стоит поправить.
  2. Зафиксируйте validationErrorCode и структуру тела ошибки в договоре или спецификации API. Не в переписке, а в документе.
  3. Отдельно проговорите с командой, что дефолтное значение 01.01.1900 для даты — это не «нет данных», а повод для отказа.
  4. Заведите в чек-листе приёмки интеграции пункт: проверить поведение при отсутствующем поле, при явном null, при неверном типе и при нарушении бизнес-правила. Четыре теста, которые снимают большую часть будущих споров.

Ограничения

Первое. Последовательность обнаружения ошибок встроена в платформу: пока запрос не прошёл типизацию, ваш код не запустится. Обойти это можно только отказом от типизации, а не настройкой.

Второе. Шаблон тела ответа — строка с экранированным JSON. Для человека, который редко лезет в конфигурацию, это место, где легко посадить лишнюю кавычку и получить нечитаемую ошибку вместо понятного сообщения. Правки — только через редактор конфигурации, с проверкой на стенде.

Третье. Пример разобран на версии 3.2. Если ваш контур на другой ветке, поведение и состав настроек лучше сверить на тестовом стенде, а не переносить конфиг копипастом в прод.

Брать или подождать

Брать — если у вас больше двух систем в интеграционном контуре и хотя бы один внешний партнёр. Настройка responseErrorSettings плюс типизация полей дают предсказуемый контракт ошибок, а это то, на что потом опираются и поддержка, и подрядчики.

Подождать — если у вас одна система, один поток данных и один разработчик. Автоматическая типизация всё равно полезна, но ради неё не нужно перестраивать процесс: сначала посмотрите, сколько реально приходит битых пакетов.

В любом случае не ждите, что двухуровневая проверка даст клиенту полный список проблем за один заход. Не даст. Планируйте документацию и цикл повторных отправок под две итерации — либо осознанно переносите часть правил на сторону отправителя.

FAQ

Клиент получит все ошибки за один ответ?

Нет. Сначала уходят ошибки типов и обязательных параметров, бизнес-правила проверяются только после их исправления. Формат ответа при этом одинаковый.

Если поле не передали, это ошибка?

Для платформы — нет. Подставится значение по умолчанию: пустая строка, 0, пустой массив или 01.01.1900 для даты. Явный null в не-nullable поле отклоняется.

Нужен ли отдельный обработчик для ошибок авторизации?

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

Что будет с корректным сообщением?

Получит HTTP 200 и уйдёт в платформу на дальнейшую обработку.

Можно ли задать текст ошибки в настройках?

Нет. В настройках задаётся только шаблон и HTTP-код. Текст и список полей заполняет тот, кто обнаружил ошибку: платформа или код обработчика.

Что делать на этой неделе

Откройте конфигурацию внешней системы и посмотрите, есть ли там блок responseErrorSettings. Если нет — вы сейчас отдаёте партнёрам ошибки в произвольном виде, и каждый из них разбирает их по-своему. Это чинится за один вечер и снимает целый класс споров в поддержке.

Дальше — четыре теста на приёмке и одна строчка в спецификации API про две итерации валидации. Дешевле, чем разбирать инцидент, где цена товара приехала строкой, а заметили это через неделю в отчёте.

Читайте также

Комментарии (1)

  • PrimeCoder Team · Официальный ответ · PrimeCoder

    Пришлите формат отчётности (дашборд / таблица / «на глаз») — подскажем минимальный набор метрик на старт.

Обсудить на сайте