Архитектура пользовательских интеграцийBETA
Взаимодействие с API позволяет системам обмениваться данными и выполнять различные действия. Для корректной работы интеграции необходимо правильно настроить запросы и аутентификацию, чтобы обеспечить безопасный и эффективный доступ к внешним сервисам.
Интеграция строится из отдельных логических блоков, каждый из которых выполняет конкретную задачу:
- Блоки — выполняют определенный тип запроса
- Подключения — содержат данные для доступа к внешнему API
Пример структуры интеграции:
app = {
schema: 2,
version: 'Номер версии',
label: 'Название интеграции',
description: 'Описание интеграции',
blocks: [],
connections: []
}
Блоки
Блок представляет собой основной исполняемый элемент интеграции. Он отвечает за выполнение конкретного запроса к внешнему API.
Блок может выполнять следующие задачи:
- Отправлять данные во внешнюю систему
- Получать и обрабатывать ответы от API
- Формировать выходные данные для следующих блоков
- Использовать переменные из контекста (например, значения, полученные ранее)
Такой блок является ключевым элементом логики интеграции, так как именно он взаимодействует с внешним сервисом.
bundle и context в блоках
В зависимости от реализации, контекст может быть использован для хранения данных между вызовами и передаваться обратно в функцию для обработки в следующем шаге.
При выполнении блока в функцию executePagination передаются дополнительные аргументы — bundle и context.
executePagination: (z, bundle, context) => {
}
Где:
- bundle содержит входные данные блока, параметры подключения и служебную информацию
- context используется для хранения состояния между вызовами блока и может быть возвращен для использования на следующем шаге выполнения
Пример функционального блока
Ниже приведен пример функционального блока, который выполняет запрос к API системы, получает список скриптов и возвращает отфильтрованные данные в качестве результата работы блока.
export const getAllScripts: IntegrationBlock<
{ onlyActive: boolean },
ICommonAuthData
> = {
label: "Получить все скрипты в системе",
description: "Блок получает все скрипты в системе",
inputFields: [
{
key: "onlyActive",
type: "boolean",
label: "Только активные скрипты",
default: true,
},
],
executePagination: (service, bundle, _context) => {
if (!bundle.authData || !bundle.authData.url) {
service.stringError("Отсутствует подключение.");
}
const explorer = new GraphQLClient(service);
const response = explorer.query<IApiResponse>(
bundle.authData.url,
`query {
automation {
script {
script_general_list {
items {
element {
id
name
enabled
}
}
}
}
}
}`
);
const items = response.data?.automation.script.script_general_list.items ?? [];
const output = items.reduce<TNormalizedItem[]>((acc, { element }) => {
if (element.name.includes("_DISABLE_")) {
return acc;
}
if (bundle.inputData.onlyActive && !element.enabled) {
return acc;
}
acc.push([element.id, element.name, element.enabled]);
return acc;
}, []);
const outputVariables: OutputBlockVariables[] = [
{ type: "Long", name: "id" },
{ type: "String", name: "name" },
{ type: "Boolean", name: "enabled" },
];
return {
output,
output_variables: outputVariables,
state: undefined,
hasNext: false,
};
}
}
Подключения
Подключения к внешним системам и сервисам используются для установления связи между интеграцией и внешними API или базами данных.
oAuth2
OAuth2 — это протокол аутентификации, который позволяет приложениям получать доступ к ресурсам без передачи логина и пароля. Протокол обеспечивает безопасную аутентификацию и упрощает процесс доступа к интегрируемым сервисам.
Сервисы, поддерживающие OAuth2, позволяют получить клиентский идентификатор и секретный ключ. Для этого необходимо перейти на официальный сайт выбранного сервиса в раздел с документацией по API и следовать инструкциям для регистрации приложения и получения необходимых данных.
Для аутентификации этим способом пользователю необходимо указать в настройках подключения параметры, полученные от сервиса.
Этот способ аутентификации используется в интеграциях с такими сервисами, как Google Drive, Google Таблицы, Microsoft SharePoint, amoCRM и другими.
Basic Auth
Этот метод аутентификации использует передачу логина и пароля пользователя для доступа к интегрируемому сервису.
Для аутентификации эти способом необходимо указать свои учетные данные в настройках подключения интеграции. Рекомендуется использовать защищенные соединения для передачи данных.
Например, этот способ аутентификации используют интеграции с инструментом управления проектами Jira.
API Key
Ключ API — это уникальный идентификатор, используемый для аутентификации запросов к API, который позволяет системам взаимодействовать между собой и обеспечивает доступ к нужным ресурсам без прохождения пользовательской аутентификации. Ключ API обычно передается в заголовках HTTP-запросов или в параметрах URL. Он служит для идентификации приложения и разрешает доступ к API сервиса.
Для получения ключа API необходимо зайти в свою учетную запись на выбранном сервисе, сгенерировать ключ и настроить для него права доступа.
Например, этот способ аутентификации используют интеграции с Proceset.
Пример блока подключений
Ниже приведен пример подключения по API-ключу. Он демонстрирует, как описываются поля авторизации и формируется URL для обращения к API.
import { IntegrationConnection } from "@infomaximum/integration-sdk";
import { ICommonAuthData } from "../types/connections";
export const basicConnect: IntegrationConnection<ICommonAuthData> = {
label: "Подключение по ApiKey",
description: "Подключение по ApiKey",
inputFields: [
{
key: "connection_apiKey",
type: "text",
label: "API-ключ",
},
{
key: "connection_host",
type: "text",
label: "Хост",
},
{
key: "connection_port",
type: "text",
label: "Порт ",
},
{
key: "host_button",
type: "button",
label: "Автоопределение хоста",
typeOptions: {
saveFields: (service, bundle) => {
const preparedHost = bundle.authData.BASE_URL.replace(
/^https?:\/\//,
""
).replace("/webhook/" + bundle.authData.GUID, "");
const [host, port = ""] = preparedHost.split(":");
return {
connection_host: host,
connection_port: port,
};
},
},
},
],
execute: (service, bundle) => {
function createUrl(host: string, port: string, apiKey: string): string {
const hasProtocol = /^https?:\/\//.test(host);
const base = hasProtocol ? host : `http://${host}`;
if (!port || port === "0") {
return `${base}/graphql?api_key=${apiKey}`;
}
return `${base}:${port}/graphql?api_key=${apiKey}`;
}
return {
apiKey: bundle.authData.connection_apiKey,
host: bundle.authData.connection_host,
port: bundle.authData.connection_port,
url: createUrl(
bundle.authData.connection_host,
bundle.authData.connection_port,
bundle.authData.connection_apiKey
),
};
},
refresh: () => {
/*Empty*/
},
};
Пример использования redirect
Механизм redirect используется при OAuth-аутентификации для перенаправления пользователя на страницу авторизации внешнего сервиса.
Пример формирования URL для авторизации:
redirect: (_service, bundle) =>
"https://login.microsoftonline.com/" +
bundle.authData.tenant_id +
"/oauth2/v2.0/authorize?" +
"response_type=code" +
"&client_id=" +
bundle.authData.client_id +
"&redirect_uri=" +
bundle.authData.redirect_url +
"&scope=User.Read Calendars.Read OnlineMeetingTranscript.Read.All OnlineMeetings.Read offline_access",
Пример использования saveFields
Метод saveFields применяется для сохранения данных авторизации, полученных после успешного OAuth-обмена.
access_token, refresh_token, expiration_time должны иметь именно такие названия при сохранении, иначе механизм обновления не сработает.
saveFields: (service, bundle) => {
const body =
"code=" +
authCode +
"&client_id=" +
clientId +
"&redirect_uri=" +
bundle.authData.redirect_url +
"&client_secret=" +
clientSecret +
"&grant_type=authorization_code";
const response = service.request<ArrayBuffer>({
url: `https://login.microsoftonline.com/${catalogIdentifier}/oauth2/v2.0/token`,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
jsonBody: body,
});
const exchangeCode = JSON.parse(new TextDecoder().decode(response.response));
const accTok = exchangeCode.access_token;
if (!accTok) {
service.stringError(
"Не удалось выполнить обмен Authorization Code на access_token.\n" +
JSON.stringify(exchangeCode.response)
);
}
return {
access_token: accTok,
refresh_token: exchangeCode.refresh_token,
expiration_time: exchangeCode.expires_in,
};
},
Была ли статья полезна?