Как правильно создать задачу в Redmine из 1С через REST API и избежать ошибки 422

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

Интеграция 1С с системой управления проектами Redmine — это эффективный способ автоматизировать передачу заявок, отслеживание ошибок и учет рабочего времени. Однако при использовании REST API программисты часто сталкиваются с неочевидными ошибками, такими как 422 Unprocessable Entity. Разберем подробно, почему это происходит и как реализовать надежный механизм создания задач.

Анализируем причину ошибки 422 Unprocessable Entity

Когда Redmine возвращает код 422, это означает, что сервер понял запрос, но его содержимое не соответствует правилам валидации. Чаще всего в теле ответа приходят уточнения: «Тема не может быть пустой», «Проект не может быть пустым» и так далее. Рассмотрим основные причины возникновения этой ситуации:

  1. Неверная структура JSON: Самая частая ошибка заключается в попытке отправить на сервер JSON в том же формате, в котором Redmine его отдает при GET-запросе. При получении данных задачи (GET) Redmine возвращает объекты (например, "project": {"id": 1, "name": "Project Name"}), но при создании задачи (POST) он ожидает плоские идентификаторы ("project_id": 1).
  2. Неправильный Content-Type: Если в заголовках запроса указан application/octet-stream или text/plain вместо application/json, сервер может некорректно интерпретировать тело запроса, посчитав его пустым.
  3. Кодировка и BOM: Платформа 1С при сохранении текста в UTF-8 может добавлять метку BOM (Byte Order Mark). Некоторые веб-серверы, на которых развернут Redmine, не умеют ее обрабатывать, что приводит к порче структуры JSON.

Шаг 1. Настраиваем авторизацию и соединение

Для взаимодействия с API Redmine лучше всего использовать персональный API-ключ. Это избавляет от необходимости передавать логин и пароль в открытом виде и упрощает настройку HTTPСоединение. Ключ передается в специальном заголовке X-Redmine-API-Key.

Рассмотрим, как правильно инициализировать соединение в 1С:


// Параметры сервера
Сервер = "redmine.yourcompany.com";
Порт = 443; // Обычно используется HTTPS
Токен = "ваш_api_ключ_из_настроек_профиля";

// Используем защищенное соединение для HTTPS
Защита = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Сервер, Порт, , , , 30, Защита);

Шаг 2. Формируем правильную структуру JSON

Выясним разницу между форматом отображения и форматом создания. Чтобы задача была успешно создана, нам необходимо передать минимальный набор обязательных полей, используя суффикс _id для ссылочных полей. Проанализируем пример корректного формирования JSON-объекта внутри 1С с использованием структуры.


ЗадачаОбъект = Новый Структура;
ДанныеЗадачи = Новый Структура;

ДанныеЗадачи.Вставить("project_id", 94);          // ID проекта (число)
ДанныеЗадачи.Вставить("tracker_id", 14);          // ID трекера (Ошибка, Поддержка и т.д.)
ДанныеЗадачи.Вставить("status_id", 1);            // ID статуса (Новая)
ДанныеЗадачи.Вставить("priority_id", 5);          // ID приоритета (Высокий)
ДанныеЗадачи.Вставить("subject", "Тестовая тема из 1С");
ДанныеЗадачи.Вставить("description", "Подробное описание проблемы");
ДанныеЗадачи.Вставить("assigned_to_id", 194);     // На кого назначена задача

ЗадачаОбъект.Вставить("issue", ДанныеЗадачи);

Обратите внимание: мы не передаем id самой задачи, так как он присваивается сервером автоматически при создании. Также мы используем project_id вместо вложенного объекта project.

Шаг 3. Сериализация в JSON без ошибок

Посмотрим на пример правильной записи JSON в строку. Важно использовать объект ЗаписьJSON, чтобы избежать проблем с экранированием кавычек и спецсимволов в тексте описания.


ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(, , , ЭкранированиеСимволовJSON.ВсеВнеBasicLatin);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
ЗаписатьJSON(ЗаписьJSON, ЗадачаОбъект);
СтрокаЗапроса = ЗаписьJSON.Закрыть();

Шаг 4. Отправка запроса и обработка результата

Теперь соберем все воедино в HTTPЗапрос. Помним о важности заголовка Content-Type.


HTTPЗапрос = Новый HTTPЗапрос("/issues.json");
HTTPЗапрос.Заголовки.Вставить("X-Redmine-API-Key", Токен);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json");

// Устанавливаем тело запроса в кодировке UTF-8 без BOM
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

Попытка
    Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    Если Ответ.КодСостояния = 201 Тогда
        Сообщить("Задача успешно создана!");
    Иначе
        Сообщить("Ошибка при создании: " + Ответ.КодСостояния);
        Сообщить(Ответ.ПолучитьТелоКакСтроку());
    КонецЕсли;
Исключение
    Сообщить("Не удалось соединиться с сервером: " + ОписаниеОшибки());
КонецПопытки;

Дополнительно: Работа с вложениями

Проанализируем ситуацию, когда к задаче нужно прикрепить файл из 1С. Это двухэтапный процесс, который часто вызывает путаницу:

  1. Загрузка файла: Сначала нужно отправить файл POST-запросом на адрес /uploads.json. В теле запроса передаются чистые двоичные данные файла (application/octet-stream). В ответ Redmine вернет token.
  2. Привязка файла к задаче: Полученный токен нужно вставить в массив uploads при формировании JSON для создания задачи.

Пример структуры вложения для основного запроса:


Вложение = Новый Структура;
Вложение.Вставить("token", "7973.a062c6e4..."); // Токен из первого запроса
Вложение.Вставить("filename", "logs.txt");
Вложение.Вставить("content_type", "text/plain");

МассивВложений = Новый Массив;
МассивВложений.Добавить(Вложение);

ДанныеЗадачи.Вставить("uploads", МассивВложений);

Рекомендации по кастомным полям

Если в вашем Redmine настроены обязательные дополнительные поля (Custom Fields), их необходимо передавать в виде массива объектов внутри структуры задачи. Выясним формат:


ДопПоле = Новый Структура;
ДопПоле.Вставить("id", 16); // ID кастомного поля
ДопПоле.Вставить("value", "Значение поля");

МассивПолей = Новый Массив;
МассивПолей.Добавить(ДопПоле);

ДанныеЗадачи.Вставить("custom_fields", МассивПолей);

Резюмируем: Для успешного создания задачи в Redmine из 1С необходимо четко соблюдать структуру JSON (использовать _id), обязательно устанавливать заголовок Content-Type: application/json и исключать BOM из передаваемой строки. Использование объекта ЗаписьJSON и HTTPСоединение с защищенным каналом сделает вашу интеграцию стабильной и безопасной.

← На главную