Иногда бывает нужно передать в сторонние внешние API на вход не только строки или числа, но и параметры более сложных типов, например, файлы. А также бывает необходимость от API получить файлы из ответа.
Допустим, у нас есть сервис, который принимает на вход один файл или массив файлов, и возвращает также файл и информацию о нем. Те файлы, которые мы хотим передать, хранятся в ELMA365 в контекстных переменных.
Для примера будем использовать сервис ConvertApi (https://www.convertapi.com/) и его функции по конвертации docx в pdf и zip. Чтобы можно было пользоваться функциями этого сервиса, нужно создать на его сайте личный кабинет и получить в нем код авторизации (secret).
Предварительно можно протестировать API-запросы через Postman. Всю информацию по запросам можно найти в документации на сайте нужного сервиса.
Для нашего сервиса нам нужны два метода:
Пример POST-запроса через Postman для конвертации docx в pdf и проверки работоспособности API:
Если ввели в «Params» значение «Secret» и указали в «Body - form-data» значения для полей «File» и «StoreFile» корректно, то получим в результате ответ как на скриншоте выше. Отметим, что для этого метода вкладывается один файл. Для других методов могут вкладывается два и более файлов в колонке «Value».
Попробуем реализовать аналогичный функционал в ELMA365. Создадим модуль «Конвертация файлов». В Настройках модуля создадим переменную «secret» (тип «Строка»), в которую добавим с формы модуля значение secret, которое получили ранее в личном кабинете.
Далее создадим два Custom Activity (Действие в БП).
Конвертация docx в pdf
Создаем первый Custom Activity «Конвертация в pdf». В нем мы напишем функцию для вызова метода ConvertApi по конвертации docx в pdf.
В контексте создадим переменные:
- «Входящий docx» с кодом «input_file_docx» и типом «Файлы – Один»,
- «Итоговый pdf» с кодом «output_file_pdf» и типом «Файлы – Один»,
- «Лог конвертации в pdf» с кодом «log_converting_pdf» и типом «Строка – Текст».
Напишем функцию action() в сценарии для отправки файлов в запросе:
Код:
async function action(): Promise<void> {
// создание объекта типа FormData
let form_data = new FormData();
if (Context.data.input_file_docx) {
try {
// получение значений для form_data: имени файла, URL, ArrayBuffer
let filename = (await Context.data.input_file_docx.fetch()).data.__name;
let fileurl = await Context.data.input_file_docx.getDownloadUrl();
let arrBuffer = await (await fetch(fileurl)).arrayBuffer();
// формирование form_data
// добавление файла
form_data.append("File", arrBuffer, filename);
// добавление строки
form_data.append("StoreFile", "true");
}
catch (err_input) {
throw new Error(`Ошибка при формировании form_data: ${err_input}`);
}
// вызов метода, в body передаем составленный ранее form_data
let res = await fetch(`https://v2.convertapi.com/convert/docx/to/pdf?Secret=${Namespace.params.data.secret}`, {
method: 'POST',
body: form_data
});
if (!res.ok) {
throw new Error(`Ошибка при отправке запроса: ${res.status} ${res.statusText}`);
}
else {
try {
// обработка JSON-ответа
let json_result = await res.json();
Context.data.log_converting_pdf = JSON.stringify(json_result);
// формирование файла с помощью createFromLink() и его запись в контекстную переменную типа "Файл"
Context.data.output_file_pdf = await Context.fields.output_file_pdf.createFromLink(json_result.Files[0].FileName, json_result.Files[0].Url);
}
catch (err_output) {
throw new Error(`Ошибка при формировании ответа: ${err_output}`);
}
}
}
}
Наша основная задача - сформировать form_data, который составит body запроса.
Для этого мы получаем из контекстной переменной «input_file_docx» значения имени файла и URL файла. А также с помощью URL определяем ArrrayBuffer. Затем пользуемся функцией append(), добавляя в form_data нужные нам для API параметры: файл и поле «StoreFile». Для каждого API будут свои поля.
Выполним запрос, обратившись к значению secret, находящегося в параметрах модуля, через Namespace.params.
Подсказка: Аналогичным образом как задали secret можно задать и значение URL API и обратиться к нему таким же образом через Namespace.params. А также при необходимости задать и значения других параметров, которые могут потребоваться в запросе и которые было бы удобно настраивать через форму модуля.
Обязательно укажем form_data как значение body.
Если запрос выполнен успешно, то получим ответ. Сперва сконвертируем его в JSON. Затем, чтобы сохранить файл в переменную типа «Файл» модуля, воспользуемся функцией createFromLink(). Подробнее про нее можно почитать в tssdk. Для создания файла в системе и его записи в переменную, укажем в параметрах функции имя и URL файлы, полученные из JSON ответа API.
В случае, если API возвращает не ссылку на файл, а сам файл, можно воспользоваться этим кодом вместо createFromLink():
Код:
let buff = await res.arrayBuffer();
Context.data.output_file_pdf = await Context.fields.output_file_pdf.create(`output-${Date.now()}.pdf`, buff);
В таком случае нам нужно получить ArrayBuffer из ответа вместо JSON и далее с помощью функции create() создать файл на основе ArrayBuffer.
Конвертация docx в zip
Создаем второй Custom Activity «Конвертация в zip». В нем мы напишем функцию для вызова метода ConvertApi по конвертации docx в zip.
В контексте создадим переменные:
- «Входящие docx» с кодом «input_files_docx» и типом «Файлы – Несколько»,
- «Итоговый zip» с кодом «output_file_zip» и типом «Файлы – Один»,
- «Лог конвертации в zip» с кодом «log_converting_zip» и типом «Строка – Текст».
Напишем функцию action() в сценарии для отправки файлов в запросе:
Код:
async function action(): Promise<void> {
// создание объекта типа FormData
let form_data = new FormData();
if (Context.data.input_files_docx) {
try {
// цикл по всем файлам массива input_files_docx
for (let one_file of Context.data.input_files_docx) {
// получение значений для form_data: имени файла, URL, ArrayBuffer
let filename = (await one_file.fetch()).data.__name;
let fileurl = await one_file.getDownloadUrl();
let arrBuffer = await (await fetch(fileurl)).arrayBuffer();
// формирование form_data
// добавление каждого файла
form_data.append("Files", arrBuffer, filename);
}
// добавление строки
form_data.append("StoreFile", "true");
}
catch (err_input) {
throw new Error(`Ошибка при формировании массива входных файлов: ${err_input}`);
}
// вызов метода, в body передаем составленный ранее form_data
let res = await fetch(`https://v2.convertapi.com/convert/any/to/zip?Secret=${Namespace.params.data.secret}`, {
method: 'POST',
body: form_data
});
if (!res.ok) {
throw new Error(`Ошибка при отправке запроса: ${res.status} ${res.statusText}`);
}
else {
try {
// обработка JSON-ответа
let json_result = await res.json();
Context.data.log_converting_zip = JSON.stringify(json_result);
// формирование файла с помощью createFromLink() и его запись в контекстную переменную типа "Файл"
Context.data.output_file_zip = await Context.fields.output_file_zip.createFromLink(json_result.Files[0].FileName, json_result.Files[0].Url);
}
catch (err_output) {
throw new Error(`Ошибка при формировании ответа: ${err_output}`);
}
}
}
}
Основное отличие от кода предыдущего Custom Activity заключается в том, что сейчас на вход подается массив файлов, а не один файл. Поэтому при формировании form_data необходимо выполнить цикл foreach, чтобы обработать все файлы из массива файлов «input_files_docx» и каждый из них поместить в form_data.
Для тестирования можно написать простой бизнес-процесс (далее по тексту: БП), где будем отправлять в модуль файлы из переменных и получать сконвертированные файлы на выходе. Исходные файлы можно заполнять, например, на форме стартового события БП.
Карта БП:
Контекст БП:
Пример настроек блока модуля:
Пример настроек задачи Получения файлов:
Запустим БП, заполним поля с исходными файлами и убедимся, что после этого БП и конвертация выполнятся успешно, и нам придет задача с нужными файлами.
Таким образом можно работать с внешними API, принимающими и отдающими файлы.
Последнее редактирование: 31 авг 2023