Camunda REST
Экспериментальный модуль
Экспериментальный модуль является полностью рабочим и протестированным, но требует дополнительной апробации и аналитики по использованию.
Поэтому API может получить незначительные изменения до полной готовности.
Camunda 7 устарела
CamundaRestModule помечен как @Deprecated, потому что Camunda 7 достигла конца жизненного цикла.
Модуль по-прежнему работает и поставляется, но новых возможностей для него не планируется.
Для новых сервисов рассмотрите Camunda 8 или движок Operaton — форк Camunda 7, развиваемый сообществом.
Модуль публикует Camunda 7 REST API приложения Kora:
он разворачивает стандартные JAX-RS-ресурсы CamundaRestResources в деплойменте RESTEasy и отдает их через отдельный HTTP-сервер Undertow.
Он используется вместе с модулем Camunda 7 BPMN: BPMN-движок выполняет процессы, а этот модуль дает HTTP-доступ к операциям Camunda 7 —
запуску экземпляров процессов, запросам задач и загрузок, корреляции сообщений и всему остальному, что предоставляет REST API движка.
Дополнительно модуль может отдавать OpenAPI-описание REST API вместе со страницами Swagger UI и Scalar.
Для запросов к REST API доступны собственные настройки CORS, логирования, метрик, трассировки и штатного завершения сервера.
Подключение¶
Зависимость build.gradle:
Модуль:
Зависимость build.gradle.kts:
Модуль:
Требует подключения модуля Camunda 7 BPMN.
Сам движок Camunda подключен к этому модулю как compileOnly-зависимость, поэтому в classpath он попадает только через camunda-engine-bpmn, который к тому же и создает обслуживаемый ProcessEngine.
CamundaRestUndertowModule наследует CamundaRestModule: базовый модуль предоставляет конфигурацию, фабрику телеметрии и стандартное JAX-RS-приложение, а Undertow-модуль добавляет HTTP-обработчик и сам сервер.
В приложении подключается CamundaRestUndertowModule — подключение только CamundaRestModule оставит REST API без транспорта.
HTTP-сервер¶
Модуль запускает отдельный независимый HTTP-сервер Undertow, выделенный под Camunda 7 REST API.
Он слушает собственный port (по умолчанию: 8081) и полностью изолирован от основного модуля HTTP-сервера:
у него собственный фильтр CORS, собственная телеметрия и собственное штатное завершение.
Таким образом, Camunda REST API и собственные контроллеры приложения работают на разных портах и не разделяют обработку запросов или конфигурацию.
По умолчанию сервер выключен и запускается опцией camunda.rest.enabled = true.
Сам REST-обработчик всегда собирается при инициализации графа — enabled определяет лишь то, будет ли открыт HTTP-слушатель.
Если указанный port уже занят, запуск падает с ошибкой Camunda HTTP Server (Undertow) failed to start, cause port '<port>' is already in use.
ProcessEngine, обслуживающий эти запросы, предоставляется модулем Camunda 7 BPMN.
Внутри контейнера Kora зависимости между двумя модулями нет: BPMN-модуль регистрирует созданный движок в статическом реестре ProcessEngines из Camunda,
а этот модуль публикует KoraProcessEngineProvider через ServiceLoader по контракту org.camunda.bpm.engine.rest.spi.ProcessEngineProvider, который и достает движок по умолчанию из этого реестра.
Данный модуль лишь открывает к движку HTTP-доступ по настроенному path (по умолчанию: /engine-rest).
Запросы обрабатываются на виртуальных потоках, поэтому вызов Camunda REST, заблокированный на базе данных, не занимает I/O-поток Undertow.
При завершении работы сервер перестает принимать новые запросы и ждет до shutdownWait (по умолчанию: 30s)
завершения уже обрабатываемых запросов, прежде чем остановиться.
Конфигурация¶
Пример полной конфигурации, описанной в интерфейсе CamundaRestConfig:
camunda {
rest {
enabled = false //(1)!
path = "/engine-rest" //(2)!
port = 8081 //(3)!
shutdownWait = "30s" //(4)!
openapi {
enabled = false //(5)!
files = [ "openapi.json" ] //(6)!
path = "/openapi" //(7)!
cache = "GZIP" //(8)!
swaggerui {
enabled = false //(9)!
path = "/swagger-ui" //(10)!
withCredentials = true //(11)!
cache = "GZIP" //(12)!
options { //(13)!
layout = "StandaloneLayout"
validatorUrl = "null"
defaultModelsExpandDepth = "0"
deepLinking = "true"
persistAuthorization = "true"
displayOperationId = "true"
filter = "true"
}
}
scalar {
enabled = false //(14)!
path = "/scalar" //(15)!
cache = "GZIP" //(16)!
}
}
cors {
enabled = false //(17)!
allowOrigin = "*" //(18)!
allowHeaders = [ "*" ] //(19)!
allowMethods = [ "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" ] //(20)!
allowCredentials = true //(21)!
exposeHeaders = [ "*" ] //(22)!
maxAge = "1h" //(23)!
}
telemetry {
logging {
enabled = false //(24)!
stacktrace = true //(25)!
mask = "***" //(26)!
maskQueries = [ ] //(27)!
maskHeaders = [ "authorization", "cookie", "set-cookie" ] //(28)!
pathFull = false //(29)!
}
metrics {
enabled = false //(30)!
slo = [ 1, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 30000, 60000, 90000 ] //(31)!
tags = { //(32)!
"key1" = "value1"
"key2" = "value2"
}
}
tracing {
enabled = true //(33)!
attributes = { //(34)!
"key1" = "value1"
"key2" = "value2"
}
}
}
}
}
- Запускает отдельный HTTP-сервер с
Camunda 7 REST API(по умолчанию:false). - Префикс пути
Camunda 7 REST API(по умолчанию:/engine-rest). - Порт отдельного HTTP-сервера
Undertow, обслуживающегоREST API(по умолчанию:8081). - Максимальное время ожидания штатного завершения HTTP-сервера (по умолчанию:
30s). - Включает отдачу файлов
OpenAPI(по умолчанию:false). - Список файлов
OpenAPIв ресурсах приложения (по умолчанию:[ "openapi.json" ]), см. OpenAPI. Значение по умолчанию — спецификация, поставляемая в составе зависимостиcamunda-engine-rest-openapi. - Путь, по которому доступны файлы
OpenAPI(по умолчанию:/openapi). При одном файле это ровно этот путь, при нескольких — префикс вида/openapi/{file}. - Режим кеширования ответов для файлов
OpenAPI:NONE,GZIPилиFULL(по умолчанию:GZIP), см. Кэширование. - Включает страницу
Swagger UI(по умолчанию:false). - Путь, по которому доступна страница
Swagger UI(по умолчанию:/swagger-ui). - Отправлять учетные данные браузера (куки, заголовок
Authorization) в запросах изSwagger UI(по умолчанию:true). - Режим кеширования ответов для страницы
Swagger UI:NONE,GZIPилиFULL(по умолчанию:GZIP). - Параметры инициализации
Swagger UI, см. Параметры Swagger UI (по умолчанию: семь значений, показанных выше). - Включает страницу
Scalar(по умолчанию:false). - Путь, по которому доступна страница
Scalar(по умолчанию:/scalar). - Режим кеширования ответов для страницы
Scalar:NONE,GZIPилиFULL(по умолчанию:GZIP). - Включает фильтр
CORS(по умолчанию:false). - Разрешенный источник для
CORS(по умолчанию не указан, опционально). Если значение не указано, фильтр возвращает заголовокOriginиз запроса, а при его отсутствии —*. - Разрешенные заголовки для
CORS-запросов (по умолчанию:[ "*" ]). - Разрешенные HTTP-методы для
CORS-запросов (по умолчанию:[ "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" ]). - Разрешена ли передача учетных данных в
CORS-запросах (по умолчанию:true). - Заголовки, доступные клиенту в
CORS-ответе (по умолчанию:[ "*" ]). - Максимальное время кеширования предварительных
CORS-запросов (по умолчанию:1h). - Включает логирование модуля (по умолчанию:
false). - Включает логирование стек-трейса при ошибке (по умолчанию:
true). - Маска, которой скрываются указанные заголовки и параметры запроса (по умолчанию:
***). - Список параметров запроса, которые нужно скрывать (по умолчанию:
[]). - Список заголовков запроса или ответа, которые нужно скрывать (по умолчанию:
[ "authorization", "cookie", "set-cookie" ]). - Логировать ли полный путь запроса вместо шаблона маршрута; если не указано, используется шаблон, кроме уровня
TRACE, где используется полный путь (по умолчанию не указан, опционально). - Включает метрики модуля (по умолчанию:
false). - Настройка SLO для метрик (по умолчанию:
io.koraframework.telemetry.common.TelemetryConfig.MetricsConfig#DEFAULT_SLO). - Теги метрик (по умолчанию:
{}). - Включает трассировку модуля (по умолчанию:
true). - Атрибуты трассировки (по умолчанию:
{}).
camunda:
rest:
enabled: false #(1)!
path: "/engine-rest" #(2)!
port: 8081 #(3)!
shutdownWait: "30s" #(4)!
openapi:
enabled: false #(5)!
files: [ "openapi.json" ] #(6)!
path: "/openapi" #(7)!
cache: "GZIP" #(8)!
swaggerui:
enabled: false #(9)!
path: "/swagger-ui" #(10)!
withCredentials: true #(11)!
cache: "GZIP" #(12)!
options: #(13)!
layout: "StandaloneLayout"
validatorUrl: "null"
defaultModelsExpandDepth: "0"
deepLinking: "true"
persistAuthorization: "true"
displayOperationId: "true"
filter: "true"
scalar:
enabled: false #(14)!
path: "/scalar" #(15)!
cache: "GZIP" #(16)!
cors:
enabled: false #(17)!
allowOrigin: "*" #(18)!
allowHeaders: [ "*" ] #(19)!
allowMethods: [ "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" ] #(20)!
allowCredentials: true #(21)!
exposeHeaders: [ "*" ] #(22)!
maxAge: "1h" #(23)!
telemetry:
logging:
enabled: false #(24)!
stacktrace: true #(25)!
mask: "***" #(26)!
maskQueries: [ ] #(27)!
maskHeaders: [ "authorization", "cookie", "set-cookie" ] #(28)!
pathFull: false #(29)!
metrics:
enabled: false #(30)!
slo: [ 1, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 30000, 60000, 90000 ] #(31)!
tags: #(32)!
key1: value1
key2: value2
tracing:
enabled: true #(33)!
attributes: #(34)!
key1: value1
key2: value2
- Запускает отдельный HTTP-сервер с
Camunda 7 REST API(по умолчанию:false). - Префикс пути
Camunda 7 REST API(по умолчанию:/engine-rest). - Порт отдельного HTTP-сервера
Undertow, обслуживающегоREST API(по умолчанию:8081). - Максимальное время ожидания штатного завершения HTTP-сервера (по умолчанию:
30s). - Включает отдачу файлов
OpenAPI(по умолчанию:false). - Список файлов
OpenAPIв ресурсах приложения (по умолчанию:[ "openapi.json" ]), см. OpenAPI. Значение по умолчанию — спецификация, поставляемая в составе зависимостиcamunda-engine-rest-openapi. - Путь, по которому доступны файлы
OpenAPI(по умолчанию:/openapi). При одном файле это ровно этот путь, при нескольких — префикс вида/openapi/{file}. - Режим кеширования ответов для файлов
OpenAPI:NONE,GZIPилиFULL(по умолчанию:GZIP), см. Кэширование. - Включает страницу
Swagger UI(по умолчанию:false). - Путь, по которому доступна страница
Swagger UI(по умолчанию:/swagger-ui). - Отправлять учетные данные браузера (куки, заголовок
Authorization) в запросах изSwagger UI(по умолчанию:true). - Режим кеширования ответов для страницы
Swagger UI:NONE,GZIPилиFULL(по умолчанию:GZIP). - Параметры инициализации
Swagger UI, см. Параметры Swagger UI (по умолчанию: семь значений, показанных выше). - Включает страницу
Scalar(по умолчанию:false). - Путь, по которому доступна страница
Scalar(по умолчанию:/scalar). - Режим кеширования ответов для страницы
Scalar:NONE,GZIPилиFULL(по умолчанию:GZIP). - Включает фильтр
CORS(по умолчанию:false). - Разрешенный источник для
CORS(по умолчанию не указан, опционально). Если значение не указано, фильтр возвращает заголовокOriginиз запроса, а при его отсутствии —*. - Разрешенные заголовки для
CORS-запросов (по умолчанию:[ "*" ]). - Разрешенные HTTP-методы для
CORS-запросов (по умолчанию:[ "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD" ]). - Разрешена ли передача учетных данных в
CORS-запросах (по умолчанию:true). - Заголовки, доступные клиенту в
CORS-ответе (по умолчанию:[ "*" ]). - Максимальное время кеширования предварительных
CORS-запросов (по умолчанию:1h). - Включает логирование модуля (по умолчанию:
false). - Включает логирование стек-трейса при ошибке (по умолчанию:
true). - Маска, которой скрываются указанные заголовки и параметры запроса (по умолчанию:
***). - Список параметров запроса, которые нужно скрывать (по умолчанию:
[]). - Список заголовков запроса или ответа, которые нужно скрывать (по умолчанию:
[ "authorization", "cookie", "set-cookie" ]). - Логировать ли полный путь запроса вместо шаблона маршрута; если не указано, используется шаблон, кроме уровня
TRACE, где используется полный путь (по умолчанию не указан, опционально). - Включает метрики модуля (по умолчанию:
false). - Настройка SLO для метрик (по умолчанию:
io.koraframework.telemetry.common.TelemetryConfig.MetricsConfig#DEFAULT_SLO). - Теги метрик (по умолчанию:
{}). - Включает трассировку модуля (по умолчанию:
true). - Атрибуты трассировки (по умолчанию:
{}).
В листинге выше показаны все доступные опции; на практике включают только то, что действительно нужно.
Типовая конфигурация публикует REST API на своем port вместе с описанием OpenAPI, страницей Swagger UI и логированием запросов:
Значения cache сопоставляются с константами перечисления буквально, поэтому их нужно писать в верхнем регистре.
OpenAPI¶
Помимо самого REST API, отдельный сервер может отдавать OpenAPI-описание API вместе со
страницами Swagger UI и Scalar.
Все три по умолчанию отключены и включаются независимо друг от друга через секцию конфигурации openapi,
и все три отдаются теми же обработчиками, что использует модуль управления OpenAPI, поэтому их поведение совпадает.
При включении страницы доступны на port REST-сервера по настроенным путям:
| Страница | Флаг конфигурации | Путь по умолчанию |
|---|---|---|
| Спецификация OpenAPI | openapi.enabled |
/openapi |
| Swagger UI | openapi.swaggerui.enabled |
/swagger-ui |
| Scalar | openapi.scalar.enabled |
/scalar |
Например, при port = 8090 и openapi.enabled = true спецификация отдается по адресу http://localhost:8090/openapi,
а Swagger UI (если включен) — по адресу http://localhost:8090/swagger-ui.
Все, что не попадает ни в эти пути, ни в префикс path REST API, отвечает 404.
По умолчанию модуль отдает OpenAPI-спецификацию, поставляемую в составе зависимости
camunda-engine-rest-openapi, поэтому у files уже есть рабочее значение по умолчанию.
Перед отправкой файла модуль заменяет в нем порт 8080 на настроенный port, а если path отличается от /engine-rest — заменяет и префикс engine-rest,
поэтому отдаваемый OpenAPI всегда соответствует актуальному адресу REST API.
Чтобы вместо этого отдавать собственную спецификацию, укажите в openapi.files один или несколько файлов в resources:
Каждый путь разрешается как ресурс classpath — сначала как записан, затем с добавленным ведущим /, поэтому openapi/my.json и /openapi/my.json указывают на один и тот же ресурс.
Файл с расширением .json отдается как text/json, любое другое расширение — как text/x-yaml.
Когда файлов несколько, публичное имя файла в URL выводится из имени файла: каталоги отбрасываются, а расширение .json, .yml или .yaml удаляется.
Так, при files = [ "openapi/engine.json", "openapi/custom.json" ] спецификации доступны по адресам /openapi/engine и /openapi/custom, а сам /openapi отвечает 404.
CORS¶
У REST-сервера есть собственный фильтр CORS, отключенный по умолчанию и включаемый через cors.enabled.
При включении фильтр оборачивает сервер целиком — и REST API, и страницы OpenAPI — и добавляет заголовки Access-Control-* к каждому ответу, не перехватывая предварительные запросы самостоятельно.
Если cors.allowOrigin не задан, фильтр возвращает в ответе заголовок Origin из запроса,
а при отсутствии заголовка Origin в запросе использует *.
Остальные параметры cors.* управляют разрешенными заголовками и методами, разрешена ли передача учетных данных,
заголовками, доступными клиенту, и временем кеширования предварительных запросов.
Заголовок, который ресурс уже выставил сам, никогда не перезаписывается, а Access-Control-Expose-Headers не добавляется вовсе, если exposeHeaders пуст.
Телеметрия¶
Запросы, обрабатываемые REST-сервером, охвачены стандартными сигналами телеметрии Kora — логированием,
метриками и трассировкой — которые настраиваются в секции telemetry.
Логирование и метрики по умолчанию отключены, трассировка по умолчанию включена; когда выключено все три, модуль подставляет пустую телеметрию и не добавляет накладных расходов на запрос.
Логирование пишется в логгер io.koraframework.http.server.common.HttpServer и создает событие CamundaRest received request перед вызовом
и событие CamundaRest succeed response (или CamundaRest errored response при ошибке) после него.
Поле operation содержит метод и шаблон маршрута, к событию ответа добавляются resultCode, statusCode и processingTime, а параметры запроса и заголовки добавляются на уровне DEBUG.
Заголовки из maskHeaders и параметры запроса из maskQueries заменяются значением mask.
В логируемой операции по умолчанию используется шаблон маршрута, а полный путь — при pathFull = true либо на уровне логгера TRACE.
Трассировка создает на каждый запрос span <METHOD> <шаблон маршрута> типа SERVER с атрибутами http.request.method, url.scheme, server.address, url.path, http.route, http.response.status_code и http.response.result_code.
Входящий контекст трассировки W3C пробрасывается в span, а результирующий контекст записывается обратно в заголовки ответа.
Метрики модуля описаны в разделе Справочник метрик.
Стандартную телеметрию можно переопределить, зарегистрировав как @Component собственного наследника DefaultCamundaRestLoggerFactory или DefaultCamundaRestMetricsFactory;
вся CamundaRestTelemetryFactory предоставляется через @DefaultComponent и также может быть заменена.
Шаблоны маршрутов¶
Метрики, трассировка и логирование опознают запрос по шаблону маршрута, а не по полному пути, поэтому /engine-rest/process-instance/{id} остается одним временным рядом независимо от количества экземпляров процессов.
Модуль не может узнать подобранный шаблон у RESTEasy, поэтому хранит встроенную таблицу всех маршрутов Camunda 7 REST API с настроенным префиксом path и сопоставляет запрос с ней.
Запрос, которому в этой таблице ничего не соответствует — неизвестный endpoint или собственный JAX-RS-ресурс, добавленный через Приложения, — все равно обслуживается, но не создает ни записи в логе, ни span'а,
а его метрика длительности записывается с тегом http.route, равным UNKNOWN_ROUTE.
Приложения¶
Модуль уже регистрирует стандартный @Tag(CamundaRest.class) jakarta.ws.rs.core.Application, который публикует стандартные
ресурсы Camunda 7 REST API (CamundaRestResources) вместе с ResteasyJackson2Provider для сериализации в JSON.
Чтобы добавить собственные ресурсы JAX-RS, зарегистрируйте свой компонент jakarta.ws.rs.core.Application, помеченный тегом @Tag(CamundaRest.class).
Все такие приложения собираются и объединяются со стандартным — их getClasses(), getSingletons() и getProperties() комбинируются —
поэтому пользовательские ресурсы отдаются на том же REST-сервере вместе со стандартными endpoint'ами Camunda и под тем же префиксом path.
Собственные ресурсы не входят во встроенную таблицу маршрутов, поэтому в метриках они отражаются как UNKNOWN_ROUTE и не логируются и не трассируются, см. Шаблоны маршрутов.