Разработка пользовательской интеграцииBETANEW
Этот раздел описывает инструменты и принципы, необходимые для разработки интеграции, включая работу с подключениями, параметрами, полями ввода и системными объектами (service
, bundle
). В рамках каждой интеграции выполняется соединение с внешними ресурсами, такими как API, базы данных или другие сервисы, с использованием настроек, указанных в блоках интеграции. Разделение интеграции на компоненты позволяет гибко настроить и адаптировать интеграции под различные требования.
Добавление интеграции в рабочее пространство
Чтобы создать собственную интеграцию в Proceset, выполните следующие шаги:
- В Панели управления в пространстве нажмите + Добавить и выберите Интеграцию.
- В открывшемся окне укажите следующие параметры:
- Название интеграции
- Ключ
- Логотип — загрузите иконку системы, с которой будет сделана интеграция, в формате .svg
- Описание (необязательно)
- Нажмите Создание.
После добавления интеграции в пространство автоматически откроется редактор кода, в котором необходимо описать функционал интеграции.
Описание кода
Интеграция состоит из следующих компонентов:
schema
— номер версии интеграции- meta — метаданные интеграции
- blocks — основные элементы интеграции, которые выполняют определенные действия. Каждый блок выполняет свою специфическую задачу, например, отправку данных в API, получение информации или выполнение вычислений.
- connections — параметры подключения к внешним системам и сервисам
Блоки интеграции могут содержать поля ввода, которые задают параметры для выполнения действий, а также объекты bundle и service для обработки данных и взаимодействия с API.
Пример структуры интеграции:
{
schema:1,
meta: {
key: 'integration_key',
name: 'Название интеграции',
description: 'Описание интеграции'
},
blocks: [],
connections: []
}
Шаблон интеграции подробно описан в разделе Пример создания пользовательской интеграции.
Meta
Раздел meta
содержит метаданные интеграции, такие как ключ, название и описание. Эти данные позволяют идентифицировать интеграцию и описать ее.
Пример метаданных интеграции:
{
meta: {
key: 'integration_key',
name: 'Пример интеграции',
description: 'Эта интеграция предназначена для демонстрации возможностей.'
}
}
Blocks
Компоненты интеграции blocks
— это основные элементы интеграции, выполняющие определенные задачи. Например, блок может получать данные из API или отправлять их в определенное приложение. Блоки необходимы для структурирования и выполнения конкретных шагов в процессе интеграции.
Пример структуры блока с полями ввода inputFields
:
{
meta: {
key: 'fetch_data_block',
name: 'Блок получения данных',
description: 'Этот блок получает данные из внешнего API'
},
inputFields: [
{
key: "api_endpoint",
type: "text",
label: "API Endpoint",
required: true
},
{
key: "access_token",
type: "text",
label: "Access Token",
required: true
}
],
executePagination: (service, bundle,context) => {
var state = context || {
page:0
}
var response = service.request({
url: bundle.inputData.api_endpoint,
method: 'GET',
headers: {
Authorization: 'Bearer ' + bundle.inputData.access_token
}
});
if (response.status !== 200) {
service.error.stringError('Ошибка запроса: ' + response.status);
}
return {
output:[response.json],
output_variables:[
{
type:"String",
name:"text"
}
],
state:state,
hasNext:false
};
}
}
Connections
Компонент интеграции connections
— это параметры подключения к внешним системам и сервисам, которые используются для установления связи между интеграцией и внешними API или базами данных.
Пример структуры подключения с использованием аутентификации Basic Auth:
{
meta: {
key: "jira_base_connection",
name: "Подключение к Jira",
description: "Подключение по логину/паролю к Jira"
},
inputFields: [
{
key: "connection_login",
type: "textPlain",
label: "Логин",
required: true
},
{
key: "connection_password",
type: "password",
label: "Пароль",
required: true
},
{
key: "connection_base_url",
type: "textPlain",
label: "URL сервера Jira",
required: true
},
{
key: "authorize_button",
type: "button",
label: "Авторизоваться",
required: false,
executeWithSaveFields: (service, bundle) => {
return {
url: bundle.authData.connection_base_url,
passHash:
"Basic " + service.base64Encode(bundle.authData.connection_login + ":" + bundle.authData.connection_password)
};
},
executeWithMessage: (service, bundle) => {
if (bundle.authData.url && bundle.authData.passHash !== "") return "Успешно авторизован!";
service.error.stringError("Не удалось авторизоваться!");
}
}
],
execute: (service, bundle) => {}
}
Пример структуры подключения с использованием аутентификации OAuth 2.0 представлен ниже.
{
meta: {
key: "connection",
name: "Подключение OAuth 2.0",
description: "Подключение OAuth 2.0"
},
inputFields: [
{
key: "subdomain_amo_crm",
type: "textPlain",
label: "Cубдомен AmoCRM",
required: true,
},
{
key: "client_id",
type: "password",
label: "Client ID",
required: true,
},
{
key: "client_secret",
type: "password",
label: "Client secret",
required: true,
},
{
key: "show_button",
type: "button",
label: "Получить redirect URL",
required: false,
executeWithSaveFields: (service, bundle) => {
return { redirect_url: bundle.authData.BASE_URL };
},
},
{
key: "redirect_url",
type: "textPlain",
label: "Redirect URL",
required: false,
},
{
key: "authorize_button",
type: "button",
label: "Авторизоваться",
required: false,
executeWithRedirect: (z, bundle) => {
return (
"https://www.amocrm.ru/oauth" +
"?mode=post_message" +
"&client_id=" +
bundle.authData.client_id +
"&redirect_uri=" +
bundle.authData.redirect_url
);
},
executeWithMessage: (service, bundle) => {
if (bundle.authData.accessToken && bundle.authData.accessToken !== "")
return "Успешно авторизован!";
service.error.stringError("Не удалось авторизоваться!");
},
executeWithSaveFields: (z, bundle) => {
const CLIENT_id = bundle.authData.client_id;
const CLIENT_secret = bundle.authData.client_secret;
const guid = bundle.authData.redirect_url
.match(/\/webhook\/.+/)[0]
.replace("/webhook/", "");
const AUTH_Code = z.hook(
(url, headers) => {
return url
.match(/code=[^&]+&?/)[0]
.replace("code=", "")
.replace("&", "");
},
guid,
20
);
if (AUTH_Code === undefined)
z.error.stringError("Не удалось получить Authorization Code.");
const exchangeCode = z.request({
url:
"https://" + bundle.authData.subdomain_amo_crm + ".amocrm.ru/oauth2/access_token",
method: "POST",
headers: {
["Content-Type"]: "application/json",
},
jsonBody: {
client_id: CLIENT_id,
client_secret: CLIENT_secret,
grant_type: "authorization_code",
code: AUTH_Code,
redirect_uri: bundle.authData.redirect_url,
},
});
var accTok = exchangeCode.response.access_token;
if (accTok === undefined)
service.error.stringError(
"Не удалось выполнить обмен Authorization Code на access_token.\n" +
JSON.stringify(exchangeCode.response)
);
return {
accessToken: accTok,
refreshToken: exchangeCode.response.refresh_token,
};
},
},
{
key: "test_button",
type: "button",
label: "Проверить подключение",
required: true,
executeWithMessage: (z, bundle) => {
if (!bundle.authData.accessToken && bundle.authData.accessToken !== "")
return "Не удалось авторизоваться!";
const req = z.request({
url:
"https://" +
bundle.authData.subdomain_amo_crm +
".amocrm.ru/api/v4/leads/pipelines",
method: "GET",
headers: {
Authorization: "Bearer " + bundle.authData.accessToken,
},
});
const status = req.status;
if (Number(status) >= 200 && Number(status) < 300)
return "Успешное подключение! Статус: " + status;
z.error.stringError(
"Не удалось подключиться! Статус: " + status + "\n" + JSON.stringify(req)
);
},
},
{
key: "un_authorize_button",
type: "button",
label: "Забыть учётную запись",
required: false,
executeWithMessage: (z, bundle) => {
return "Я забыл твой токен.";
},
executeWithSaveFields: (z, bundle) => {
return { accessToken: "", refreshToken: "" };
},
},
],
execute: (z, bundle) => {},
}
Поля ввода inputFields
Поля inputFields
— это поля ввода, которые позволяют пользователю задавать параметры для блоков интеграции. Они необходимы для настройки параметров, которые будут использоваться в ходе выполнения блока.
Ниже приведены примеры различных полей ввода.
Тип поля | Назначение | Пример использования |
---|---|---|
text | Ввод текста | Комментарий к действию |
textPlain | Ввод простого текста без форматирования | Ключ API, идентификатор объекта |
switcher | Переключатель (вкл/выкл) | Активация сессий |
numberPlain | Ввод числовых значений | Количество, идентификатор |
textArea | Ввод большого объема текста | Сообщение |
sqlArea | Ввод SQL-запроса | Запрос к базе данных |
jsArea | Ввод JavaScript-кода | Вычисления |
jsonArea | Ввод JSON-объекта | Передача вложенных параметров в запросе |
select | Выбор одного значения из списка | Метод HTTP-запроса |
multiselect | Выбор нескольких значений из списка | Роли пользователей, теги |
keyValue | Ввод пар ключ-значение | HTTP-заголовки, параметры запроса |
Поле text
Поле text
— однострочное текстовое поле для ввода строковых значений.
{
key: "comment",
type: "text",
label: "Комментарий",
required: false
}
Поле textPlain
Поле textPlain
— аналог поля text
для ввода простого текста без форматирования.
{
key: "api_key",
type: "textPlain",
label: "Ключ API",
required: true
}
Поле switcher
Поле switcher
— переключатель, может быть включен или выключен.
{
key: "session_mode",
type: "switcher",
label: "Активировать режим сессий",
required: false
}
Поле numberPlain
Поле numberPlain
— предназначено для ввода числовых значений.
{
key: "value",
type: "numberPlain",
label: "Значение",
required: true
}
Поле textArea
Поле textArea
— предназначено для ввода большого количества текста.
{
key: "message",
type: "textArea",
label: "Сообщение",
required: true
}
Поле sqlArea
Поле sqlArea
— предназначено для ввода SQL-запросов.
{
key: "sql_query",
type: "sqlArea",
label: "SQL-запрос",
required: true
}
Поле jsArea
Поле jsArea
— предназначено для ввода JS-кода.
{
key: 'javascript',
type: 'jsArea',
label: 'JavaScript',
required: true
}
Поле jsonArea
Поле jsonArea
— предназначено для ввода JSON-объектов.
{
key: 'returned_data',
type: 'jsonArea',
label: 'Возвращаемые данные',
required: false
}
Поля select и multiSelect
Поля select
и multiSelect
— предназначены для выбора из предопределенных значений в виде раскрывающегося списка:
select
— поле для выбора одного значения из спискаmultiSelect
— поле для выбора нескольких значений из списка
Оба типа полей могут принимать значения для choices
в трех форматах:
- Объект с парой «ключ-значение»
{ key: "http_method", type: "select", label: "Метод", required: true, choices: { GET: "GET", POST: "POST" } },
- Массив объектов с полями
label
иvalue
{ key: "user_roles", type: "multiSelect", label: "Роли пользователей", required: true, choices: [ { label: "Администратор", value: "admin" }, { label: "Пользователь", value: "user" }, { label: "Гость", value: "guest" } ] },
- Массив строк
{ key: "data_type", type: "multiSelect", label: "Тип данных", required: false, choices: ["Строка", "Число", "Дата"] }
Поле keyValue
Поле keyValue
— предназначено для ввода пар «ключ-значение» и может быть использовано при создании параметров запроса. Этот тип поля можно настроить двумя способами:
- Указание типов полей для ключа и значения
{ key: "headers", type: "keyValue", label: "Заголовки", label2: "Ключ и значение", subFieldKeyType: "textPlain", subFieldValueType: "textPlain", required: true }
- Указание списка ключей, которые будут иметь текстовые значения
{ key: "keyValue_2", type: "keyValue", label: "Дополнительные параметры", label2: "Имя параметра и значение", subFieldKeyType: "textPlain", subFieldValueType: "textPlain", keys: ["Параметр 1", "Параметр 2", "Параметр 3"], required: false }
Доступные методы inputFields
Метод executeWithRedirect()
используется для взаимодействия с Redirect
, например, для открытия окна авторизации. Этот метод позволяет перенаправить пользователя на другую страницу или окно, что может быть полезно для аутентификации или получения разрешений.
Метод executeWithSaveFields()
позволяет взаимодействовать с authData
. Этот метод используется для сохранения данных аутентификации или других полей, которые могут понадобиться в дальнейшем. Он обеспечивает возможность работы с данными, полученными в процессе авторизации.
Метод executeWithMessage()
выводит сообщение в блок. Этот метод позволяет отображать сообщения пользователю, например, об успешном завершении операции или об ошибках. Это улучшает взаимодействие с пользователем, предоставляя ему обратную связь о выполненных действиях.
Методы выполняются в указанном порядке.
Использование объекта service
Объект service
предоставляет набор методов для взаимодействия c API, вывода ошибок, а также работы с хуками и итераторами.
Доступные методы объекта service
Метод base64Encode
— производит base64-кодирование входной строки. На вход принимает строку, которую необходимо закодировать.
service.base64Encode()
Метод base64Decode
— производит base64-декодирование входной строки. На вход принимает строку, которую необходимо декодировать в формате base64
.
service.base64Decode()
Метод request
— выполняет HTTP-запрос. Ожидает на вход объект с конфигурацией запроса. Параметры этого объекта указаны в таблице ниже.
Параметр | Обязательный | Описание |
---|---|---|
url | Да | Ссылка на ресурс, на который нужно выполнить запрос |
method | Да | Метод с которым будет выполнен запрос. Доступные методы: - GET - POST - PATCH - PUT - DELETE |
headers | Нет | Список заголовков для HTTP/1.1 |
jsonBody multipartBody | Зависит от метода | Обязательный для POST /PATCH /PUT |
service.request({
url: request_url,
method: "POST",
headers: {
Authorization: `Bearer ${bundle.authData.access_token}`,
"Content-Type": "application/json"
},
jsonBody: {
note: bundle.inputData.note
}
})
Метод hasNext
— возвращает true
или false
в зависимости от того, есть ли еще элементы во входном итераторе блока.
service.hasNext()
Метод next
— если есть следующий элемент в итераторе, вызов этого метода обновит все значения полей маппинга на значения соответствующие следующему элементу итератора. Вызов этого метода автоматически сокращает количество элементов в выходном итераторе.
service.next()
Метод index
— возвращает текущий номер итерации.
service.index()
Метод hook
— обрабатывает ответ от ресурса, к которому происходит подключение.
{
key: "authorize",
type: "button",
label: "Авторизоваться",
required: false,
executeWithRedirect: (service, bundle) => {
return `https://gitlab.com/oauth/authorize?client_id=${bundle.authData.client_id}&redirect_uri=${bundle.authData.redirect_url}&response_type=code`;
},
executeWithSaveFields: (service, bundle) => {
const match = bundle.authData.redirect_url.match(/\/webhook\/.+/);
let guid = "";
if (match) {
guid = match[0].replace("/webhook/", "");
const AUTH_Code = service.hook(
(url, headers) => {
return url
.match(/code=[^&]+&?/)[0]
.replace("code=", "")
.replace("&", "");
},
guid,
20
);
if (AUTH_Code === undefined) service.error.stringError("Не удалось получить Authorization Code.");
const exchangeCode = service.request({
url: `https://gitlab.com/oauth/token`,
method: "POST",
headers: {
["Content-Type"]: "application/json"
},
jsonBody: {
client_id: bundle.authData.client_id,
client_secret: bundle.authData.client_secret,
grant_type: "authorization_code",
code: AUTH_Code,
redirect_uri: bundle.authData.redirect_url
}
});
var accTok = exchangeCode.response.access_token;
if (accTok === undefined)
service.error.stringError(
"Не удалось выполнить обмен Authorization Code на access_token.\n" + JSON.stringify(exchangeCode.response)
);
return {
access_token: accTok,
refresh_token: exchangeCode.response.refresh_token
};
} else {
service.error.stringError("Не удалось авторизоваться!");
}
},
executeWithMessage: (service, bundle) => {
if (bundle.authData.access_token && bundle.authData.access_token !== "") return "Успешно авторизован!";
service.error.stringError("Не удалось авторизоваться!");
}
}
Метод error.stringError
— служит для вывода текста ошибки. В качестве параметра принимает строку, которая отобразится в блоке в случае возникновения ошибки.
service.error.stringError()
Использование объекта bundle
Пользовательские данные из полей ввода доступны в коде интеграции через объект bundle
.
Объект bundle
содержит два основных компонента, которые предоставляют доступ к введенной информации:
С помощью этих данных блок настраивает запросы и выполняет необходимые действия.
bundle.authData
Компонент bundle.authData
хранит учетные данные, которые настраиваются в разделе подключений (connections
).
Все поля ввода из подключения автоматически становятся доступны через bundle.authData
. Эти данные необходимы для взаимодействия с API и внешними сервисами.
Пример:
При настройке подключения с полями api_key
и api_url
эти значения станут доступны через bundle.authData
для использования в запросах вашего блока.
execute: (service, bundle) => {
var response = service.request({
url: bundle.authData.api_url + '/data',
method: 'GET',
headers: {
Authorization: 'Bearer ' + bundle.authData.api_key
}
});
if (response.status !== 200) {
service.error.stringError('Ошибка запроса: ' + response.status);
}
return {
output: () => ({
data: response.json
})
};
}
bundle.inputData
Компонент bundle.inputData
хранит данные, которые пользователь вводит в поля ввода блока (inputFields
).
Эти данные позволяют настраивать параметры запросов и выполнять другие действия внутри блока.
Все поля ввода, настроенные в блоке, автоматически становятся доступными через bundle.inputData
.
Пример:
Если в блоке есть поля ввода api_endpoint
и access_token
, их значения будут доступны через bundle.inputData
для использования при настройке запроса.
execute: (service, bundle) => {
var response = service.request({
url: bundle.inputData.api_endpoint,
method: 'GET',
headers: {
Authorization: 'Bearer ' + bundle.inputData.access_token
}
});
if (response.status !== 200) {
service.error.stringError('Ошибка запроса: ' + response.status);
}
return {
output: () => ({
data: response.json
})
};
}
Передача файлов
Интеграции поддерживают передачу файлов во внешние системы с использованием multipartBody
. Это используется, например, для прикрепления файлов к задачам в сторонних системах.
Для загрузки файлов в систему используйте блоки автоматизации для работы с файлами.
multipartBody
— это массив объектов, каждый из которых представляет собой часть данных, отправляемых в запросе.
В представленном ниже примере multipartBody
содержит один объект, который описывает файл, предназначенный для прикрепления к задаче.
Пример:
var response = service.request({
url: `${bundle.authData.url}/rest/api/2/issue/${bundle.inputData.issueIdOrKey}/attachments`,
method: "POST",
headers: {
Authorization: bundle.authData.passHash,
"X-Atlassian-Token": "nocheck"
},
multipartBody: [
{
key: "file",
fileValue: bundle.inputData.attachment,
fileName: bundle.inputData.attachment_name,
contentType: "application/octet-stream"
}
]
});
Структура объекта в multipartBody
:
key: "file"
— имя поля, под которым файл будет доступен на сервере. В приведенном примере поле называется"file"
, что соответствует ожиданиям API для загрузки вложенийfileValue: bundle.inputData.attachment
— значение, представляющее собой сам файл, который будет загружен. Оно должно содержать данные файла, которые вы хотите прикрепитьfileName: bundle.inputData.attachment_name
— имя файла, которое будет использоваться на сервере. Оно может включать расширение файла, чтобы сервер мог правильно определить тип содержимогоcontentType: "application/octet-stream"
— это MIME-тип файла. В приведенном примере используется общий тип для двоичных данных, что позволяет серверу обрабатывать файл как поток байтов. В зависимости от типа файла, можно указать более специфичный MIME-тип (например,image/jpeg
для изображений илиapplication/pdf
для PDF-документов)
Была ли статья полезна?