ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Camunda Platform REST API OpenAPI 文档自动生成:基于 FreeMarker 模板的 openapi.json 构建体系

Camunda Platform REST API OpenAPI 文档自动生成:基于 FreeMarker 模板的 openapi.json 构建体系 Camunda Platform REST API OpenAPI 文档自动生成基于 FreeMarker 模板的 openapi.json 构建体系【免费下载链接】camunda-bpm-platformCamunda 7 CE is End of Life (EoL). Please check out Camunda 8 instead (https://github.com/camunda/camunda) or read about Camunda 7 Enterprise End of Life (https://camunda.com/blog/2025/02/camunda-7-enterprise-end-of-life-extension/) – Camunda 7 CE was a flexible framework for workflow and decision automation using BPMN and DMN.项目地址: https://gitcode.com/GitHub_Trending/ca/camunda-bpm-platform导读本文围绕 Camunda Platformcamunda-bpm-platform仓库中的engine-rest/engine-rest-openapi模块系统讲解 Camunda REST API 的 OpenAPI 3.0.2 文档是如何从源码模板自动生成的包括mvn clean install触发的四阶段构建流水线、FreeMarker 模板的目录结构与编写规范main.ftl、lib/utils.ftl、models、paths、commons、宏macro体系的设计意图以及评审Review与质量保障流程。读完本文你将掌握如何为一个新的 REST 端点添加 OpenAPI 描述、如何正确使用parameter/property/requestBody/response等宏、如何通过排序/分页公共模板保持文档一致性并理解生成出的 openapi.json 如何反向驱动 Java Client 生成与 WireMock 冒烟测试。一、模块定位一份 openapi.json 覆盖整个 Engine REST APIengine-rest/engine-rest-openapi是 Camunda Platform 中专门负责OpenAPI 文档生成的 Maven 模块artifactId 为camunda-engine-rest-openapi。它的核心目标非常单一解析一组 FreeMarker 模板生成一份格式化良好的openapi.json其中包含 Camunda Engine REST API 的完整 OpenAPI 文档。该文档对齐OpenAPI Specification 3.0.2OpenAPI 3.0.2 规范中的info、servers、tags、paths、components/schemas、securitySchemes等对象均在生成结果中体现。从 pom.xml 可以看到模块还依赖同仓库的camunda-engine-rest-openapi-generator模块TemplateParser、SchemaValidator两个 Java 类并声明了 openapi-generator-maven-plugin、WireMock、AssertJ 等测试依赖。模块当前处于7.24.0-SNAPSHOT版本仓库快照版本实际发布版本以仓库 pom 为准。二、构建流水线一次mvn clean install的四阶段原文档明确指出构建命令为mvn clean install在 pom.xml 中构建被编排为四个相互衔接的阶段全部通过 Maven 插件绑定到生命周期中阶段 1模板解析生成格式化 openapi.jsonexec-maven-plugin的generate-openapi-json执行体绑定在generate-resources阶段调用主类org.camunda.bpm.engine.rest.openapi.generator.impl.TemplateParser参数为${project.basedir}/src/main/templates模板源目录main.ftl主模板入口${generated-directory}/openapi.json输出文件即target/generated-sources/openapi-json/openapi.json${project.build.directory}中间调试输出目录从 TemplateParser.java 的实现可以看到完整处理流程使用 FreeMarkerConfiguration.VERSION_2_3_29加载main.ftl模板createTemplateData()扫描模板目录构建模板数据模型modelsDTO 名 → 包路径的映射按名称字典序排序与endpoints端点路径 → HTTP 方法列表的映射同样字典序排序模板渲染后先写出一份带时间戳的intermediate-openapi-*.json中间文件便于调试再用 GsonsetPrettyPrinting()serializeNulls()对 JSON 进行格式化并落盘为最终openapi.json。值得注意的是路径解析约定resolvePaths端点的 URL 路径直接从文件系统的目录结构推导——例如src/main/templates/paths/process-instance/count/get.ftl会被解析为GET /process-instance/count。模板文件名去掉.ftl后缀即 HTTP 方法名。阶段 2Schema 校验同一阶段的validate-openapi-json执行体调用org.camunda.bpm.engine.rest.openapi.generator.impl.SchemaValidator使用仓库内置的 schema.jsonOpenAPI 3.0 官方 JSON Schema 的本地副本取自 2020-02-11对生成的 openapi.json 做结构校验。SchemaValidator.java 使用networknt的JsonSchemaFactory加载 schema 并validate()生成的文档一旦出现任何ValidationMessage错误直接抛出RuntimeException(Schema validation errors\n messages)使构建失败。这保证了模板变更不会产出结构非法的 OpenAPI 文档。阶段 3从 openapi.json 生成 Java Clientopenapi-generator-maven-plugin版本 4.2.3的generate-java-client执行体绑定在generate-test-sources阶段以刚生成的openapi.json为输入inputSpec输出到target/camunda-openapi-clientgeneratorNamejava并配置dateLibrarylegacy。随后build-helper-maven-plugin把生成的客户端源码加入测试源码目录。这一阶段意味着每改动一次模板都会立即重新生成一份可编译的 Java Client作为文档可消费性的即时验证。阶段 4针对生成客户端的冒烟测试测试代码位于 engine-rest/engine-rest-openapi/src/test使用WireMock对生成的客户端做冒烟测试例如DeploymentTest.java部署相关端点ProcessInstanceTest.java流程实例相关端点BasicAuthenticationTest.java基础认证流程这些测试用 WireMock 模拟真实 REST 服务再通过生成的 Java Client 发起调用从而验证OpenAPI 文档 → 客户端 → 实际 HTTP 语义整条链路的正确性。pom 中的swagger-annotations、okhttp、gson、gson-fire、jsr305、commons-lang3等依赖正是生成客户端运行所需的支撑库。三、模板目录结构文档的源代码OpenAPI 文档本身是产物FreeMarker 模板才是真正的源代码。原文档给出的模板结构如下对应 src/main/templates 目录--main.ftl --lib | --utils.ftl | --commons | | --pagination-params.ftl | | --process-instance-query-params.ftl | | --sort-params.ftl | | --sort-props.ftl --models | --org/camunda/bpm/engine/rest/dto | | --ExceptionDto.ftl | | --history | | | --HistoricProcessInstanceQueryDto.ftl | | --repository | | | --DeploymentDto.ftl | | | --ProcessDefinitionDto.ftl | | --runtime | | | --ActivityInstanceDto.ftl --paths | --deployment | | --create | | | --post.ftl | --process-instance | | --get.ftl | | --suspended | | | --put.ftl | | --{id} | | | --delete.ftl | | | --variables | | | | --{varName} | | | | | --data | | | | | | --get.ftl | | | | | | --post.ftl | | | | | --delete.ftl实际仓库中的目录比文档示例更庞大lib/commons 下有约 40 个可复用模板task-query-params.ftl、historic-incident-query-params.ftl、statistics-query-params.ftl、deployment-query-params.ftl等paths 下按资源组织了几十个子目录authorization、batch、deployment、execution、external-task、history、process-instance、process-definition、task等models/org/camunda/bpm/engine/rest/dto 下有约 195 个 DTO 模板。各部分的职责划分如下目录/文件职责main.ftlOpenAPI 文档顶层骨架版本、info、servers、tags、paths、componentslib/utils.ftl全部宏macro的定义路径与模型模板共同使用lib/commons/*.ftl可复用的参数/属性片段分页、排序、各类查询参数models/...请求/响应体引用的 DTO 定义目录结构与 Java 包名对齐paths/...每个 REST 端点的操作定义目录结构即 URL 路径四、main.ftlOpenAPI 文档的顶层骨架main.ftl 是模板解析的入口在 pom 中作为第二个参数传给TemplateParser。它负责输出 OpenAPI 3.0.2 文档的全局信息openapi 版本固定输出openapi: 3.0.2info标题Camunda Platform REST API、描述、版本${cambpmVersion}来自 Jar 包的ImplementationVersion、LicenseApache License 2.0externalDocs指向 Camunda REST API 参考文档servers通过lib.server宏输出三种服务端地址——默认引擎http://{host}:{port}/{contextPath}默认localhost:8080/engine-rest、命名引擎含/engine/{engineName}路径变量、自定义 URL 服务器tags为每个资源定义一个标签共 50 个左右如Authorization、Deployment、Process Instance、Task、Task Attachment、Task Comment、Task Identity Link、Historic Process Instance等。子资源必须使用父资源标签作为前缀如Task与Task Attachmentpaths遍历endpoints数据模型对每个 URL 路径、每个 HTTP 方法导入对应的method.ftl并调用其endpoint_macrosecurity / components声明basicAuthHTTP 基础认证安全方案components/schemas遍历models数据模型对每个 DTO 导入对应模板并调用其dto_macro。main.ftl还定义了文档链接的基础变量docsUrl https://docs.camunda.org/manual/${docsVersion}其中docsVersion由 TemplateParser.resolveVersions 根据包版本推导SNAPSHOT版本映射为developalpha版本映射为latest正式版本则取7.x前缀——这是模板内大量 User guide 是整个生成体系的标准库定义了路径与模型模板中高频使用的宏宏用途关键参数parameter生成查询/路径参数的 JSON 对象name、location、type、desc可选enumValues、defaultValue、format、required、lastparameters批量生成一组查询参数object参数集合、skip跳过列表、lastproperty生成 DTO 属性的 JSON 对象name、type可选format、nullable、enumValues、minimum、deprecated、itemType、dto、additionalProperties、addProperty、lastproperties批量生成一组属性同上dto生成 DTO 的 schema 定义type、title、desc、required、extends触发allOf继承requestBody生成请求体mediaType、dto/flatType、requestDesc、examplesresponse生成 HTTP 响应对象code、desc可选dto、array、additionalProperties、mediaType、binary、examples、lastmultiTypeResponse生成多 content-type 的响应types数组server生成 server 对象url、variables、descendpointInfo生成操作的元信息idoperationId、tag、desc可选deprecated、summaryremoveIndentation函数压缩描述中的多级缩进文本几个需要重点理解的实现细节逗号,控制所有宏都以last参数控制 JSON 对象间的逗号输出——最后一个条目传last true时不输出逗号其余输出。这是保证最终 JSON 语法正确的关键约定原文档反复强调不要遗漏。nullable 的默认策略property 宏 中当类型为boolean、string、array或带有format、dto引用时nullable默认输出nullable: true目的是兼容 C# 客户端对字段是否可为 null的显式声明需求只有确定必填的属性才通过nullable false关闭。typerefproperty宏支持type refdto xxx输出$ref指向#/components/schemas/xxxarray与additionalProperties组合支持输出items/additionalProperties的内联对象或$ref。204 响应response 宏 对204 No Content不生成content块responseContentMediaType对application/xhtmlxml、二进制流等媒体类型输出format: binary的字节流 schema。server 宏通过 FreeMarker 的#list variables as name, default遍历输出带默认值的 URL 变量。原文档特别提醒这些宏在路径与模型模板中被大量使用建议先熟悉它们但如果某个端点/DTO 过于复杂不使用宏、手写 JSON 也是允许的。宏缺少参数时可以直接补充但必须同步修改所有调用点。部分参数是强制的多数场景下的name与description部分是可选的锦上添花参数minimum、defaultValue、deprecated。六、modelsDTO 定义的编写规范models目录存放请求/响应体中出现的所有 DTO且遵循以下约定命名与包结构对齐 Java DTO例如 Java 类org.camunda.bpm.engine.rest.dto.ExceptionDto.java位于 engine-rest/engine-rest/src/main/java/org/camunda/bpm/engine/rest/dto/ExceptionDto.java对应模板 models/org/camunda/bpm/engine/rest/dto/ExceptionDto.ftl保持 OpenAPI 属性与 Java DTO 尽可能一致当某属性对特定端点不适用时在端点描述中显式说明例如 process-instance/suspended/put.ftl 中ProcessInstanceSuspensionStateDto的historicProcessInstanceQuery属性在批量暂停场景的适用性说明。模型自动解析TemplateParser.resolveModels()递归扫描models目录从文件路径中的org包名截取包路径模型按名称字典序自动排序。因此/models目录只放文档中实际用到的模型宏与可复用片段必须放进lib/commons禁止创建空目录。用dto宏定义模型所有 DTO 模板都应通过dto宏包裹property宏。对于存在继承关系的 DTO如TriggerVariableValueDto extends VariableValueDtodto宏的extends属性会生成 OpenAPI 的allOf语法。仓库示例 TriggerVariableValueDto.ftl#macro dto_macro docsUrl lib.dto extends VariableValueDto lib.property name local type boolean last true desc Indicates whether the variable should be a local variable or not. If set to true, the variable becomes a local variable of the execution entering the target activity. / /lib.dto /#macro渲染后即生成{allOf: [ {...本地属性...}, {$ref: #/components/schemas/VariableValueDto} ]}。响应可能是两种 DTO 的情况当响应的具体 DTO 取决于请求参数时如消息关联MessageCorrelationResultDto与其子类MessageCorrelationResultWithVariableDto建议直接使用包含全部属性的那个 DTO 作为响应 schema并明确记录哪些属性在哪些场景不适用。原文档提示某些场景可考虑oneOfdiscriminatorOpenAPI 3.0.2 支持但必须额外测试因为部分客户端生成器对该写法支持不佳。不要忘记last true每个property宏的最后一个属性必须传last true由宏负责 JSON 逗号。含排序/分页的 DTO应复用lib/commons中的公共模板见下文。七、paths端点定义的编写规范paths目录存放 REST API 全部端点的操作定义核心规则如下目录结构即 URL 路径每个资源一个文件夹如/paths/process-instance、/paths/deployment。端点路径由目录自动推导——GET /process-instance/count对应/paths/process-instance/count/get.ftl。因此必须保持/paths目录干净除端点定义外不放任何多余文件可复用片段一律进lib/commons同样禁止空目录端点路径按字典序自动排序。HTTP 方法即模板文件名get.ftl、post.ftl、put.ftl、delete.ftl、options.ftl原文档示例中写为post.frl系笔误实际为post.ftl。动态路径参数动态端点用花括号目录表达如process-instance/{id}/variables/{varName}/data且路径参数id、varName必须出现在端点定义中并标记为required通过parameter宏的location path与required true。operationId 唯一每个端点定义必须有唯一的operationId它直接用于客户端生成。大多数情况下直接采用 Java 方法名如deleteProcessInstancesAsync无法采用时按 Java 命名规范自定义。async 端点的 C# 碰撞规避对异步端点在operationId后追加Operation后缀防止 C# 客户端生成时与同步方法冲突。原文档示例setExternalTaskRetriesAsync→setExternalTaskRetriesAsyncOperationmodifyProcessInstanceAsync→modifyProcessInstanceAsyncOperation。相似端点拆分路径不同但几乎相同的端点如获取活动实例统计在不同资源下的变体必须拆分为不同文件并各自分配唯一operationId公共部分可抽到lib/commons。必填的内容要素每个端点必须包含——所属资源的tag如Process instance、Deploymentdescription与summarysummary 通常对应 REST API 文档页标题至少一个 HTTP 响应对象请求体尽量使用 DTO始终先查看对应 Java DTO 的字段避免只靠端点描述拼凑无 DTO 的请求体。以 process-instance/suspended/put.ftl 为完整范例可以看到endpointInforequestBody带 3 个示例responses204 与 400ExceptionDto的典型组合#macro endpoint_macro docsUrl { lib.endpointInfo id updateSuspensionState tag Process Instance summary Activate/Suspend In Group desc Activates or suspends process instances by providing certain criteria: ... / lib.requestBody mediaType application/json dto ProcessInstanceSuspensionStateDto examples [example-1: { summary: PUT /process-instance/suspended, description: Suspend Process Instance By Process Definition Id, value: { processDefinitionId : aProcDefId, suspended : true } }, ...] / responses : { lib.response code 204 desc Request successful./ lib.response code 400 dto ExceptionDto last true desc Bad Request .../ } } /#macro八、commons排序、分页与复用lib/commons存放可复用的公共模板原文档重点介绍了三类1. 排序sortingsort-params.ftlsort-props.ftl使用方式先assign一个sortByValues枚举列表再#include对应模板若该排序属性是最后一个参数/属性还需取消注释last true。原文档示例#-- #assign last true -- #-- remove comment if last param -- #assign sortByValues [instanceId, definitionId, definitionKey, definitionName, definitionVersion, businessKey, startTime, endTime, duration, tenantId] #include /lib/commons/sort-props.ftl 从 sort-props.ftl 的实现可以看到该模板输出sortBy枚举来自sortByValues与sortOrder枚举固定为asc/desc两个属性若传了sortParamsDto还会追加一个parameters引用属性。模板注释解释了设计缘由sortBy的取值必须动态定义且不同 Query 端点的排序属性集合不同因此不能写死在dto宏里而必须显式#include。2. 分页paginationpagination-params.ftl只要端点参数包含firstResult与maxResults就应使用它。从 pagination-params.ftl 的实现可见它输出两个integer类型的查询参数firstResult返回结果的起始索引与maxResults最多返回条数超出时返回较少结果。使用方式同样是先设定last再 include#-- #assign last true -- #-- remove comment if last param -- #include /lib/commons/pagination-params.ftl 3. 复用reuse当同一组参数在多个端点反复出现时可自定义模板并复用。原文档给出的范例是 process-instance-query-params.ftl被getProcessInstancesCount与getProcessInstances两个端点共同引用。仓库中这样的模板非常多例如task-query-params.ftl、external-task-query-params.ftl、historic-process-instance-query-params.ftl、authorization-query-params.ftl、deserialize-values-parameter.ftl等它们保证了同类查询端点参数描述的一致性。九、描述、格式、可空性与示例写作文档的四个关键规范1. 描述文本Descriptions描述支持 Markdown 语法monospace代码、*italic*/_italic_斜体、**bold**/__bold__粗体、* bullet point列表。文本规范包括使用Unix 换行符LF链接使用 Markdown 语法通过${docsUrl}变量解析官方文档链接docsUrl在main.ftl中定义为https://docs.camunda.org/manual/${docsVersion}例如User guide单行长度不超过120 字符使用缩进与换行拆分长描述提升可读性模板渲染时会由removeIndentation函数统一压缩缩进。原文档示例流程实例修改指令端点description: Submits a list of modification instructions to change a process instances execution state. A modification instruction is one of the following: * Starting execution before an activity * Starting execution after an activity on its single outgoing sequence flow * Starting execution on a specific sequence flow * Canceling an activity instance, transition instance, or all instances (activity or transition) for an activity Instructions are executed immediately and in the order they are provided in this requests body. Variables can be provided with every starting instruction. The exact semantics of modification can be read about in the [User guide](https://docs.camunda.org/manual/develop/user-guide/process-engine/process-instance-modification/).2. 格式Formatsformat字段进一步限定属性/参数的类型语义详见 OpenAPI 3.0.2 规范的dataTypeFormat。本仓库文档常用的格式为int32、binary、date-time。例如日期属性一律标注date-time格式lib.property name startedBefore type string format date-time description Restrict to instances that were started before the given date. By default (https://docs.camunda.org/manual/${docsVersion}/reference/rest/overview/date-format/), the date must have the format yyyy-MM-ddTHH:mm:ss.SSSZ, e.g., 2013-01-23T14:42:45.0000200. /标注format能显著提升生成客户端的可用性。特别注意当date-time出现在 GET 请求的 URL 参数中时必须按 Camunda 的日期格式约定做正确的 URL 编码。3. 可空性Nullable默认情况下boolean、string、array、dto类型的属性会自动开启nullable: true以生成对 C# 客户端更友好的宽松规范字段是否可为 null 由客户端显式声明。只有在确定必填的属性上才显式关闭lib.property name version type integer format int32 nullable false desc The version of the process definition that the engine assigned to it. /4. 示例ExamplesrequestBody与response宏都支持examples参数约定如下示例内容用单引号包裹而非双引号因为示例内包含引号需要转义允许多个示例每个示例是examples数组中的一个独立 JSON 对象如example-1、example-2每个示例必须有唯一名称可添加description与/或summaryvalue属性必填承载示例内容。原文档示例为SetJobRetriesByProcessDto请求体配置示例并说明historicProcessInstanceQuery在该场景下是 Unallowed propertylib.requestBody mediaType application/json dto SetJobRetriesByProcessDto requestDesc Please note that if both processInstances and processInstanceQuery are provided, then the resulting execution will be performed on the union of these sets. **Unallowed property**: historicProcessInstanceQuery examples [example-1: { value: { retries: numberOfRetries, processInstances: [aProcess, secondProcess], processInstanceQuery: { processDefinitionId: aProcessDefinitionId } } }/十、Reviews模板变更的质量评审清单由于 OpenAPI 文档是由目录结构与模板间接推导的错误的路径、缺失的响应、不规范的 operationId 都不易直接察觉因此原文档给出了一套评审Review清单宏变更回归若修改了utils.ftl中的宏请将上次构建的openapi.json与本次待评审版本做对比确保所有端点在新宏下仍然完整核对端点路径路径由目录结构推导肉眼不易发现错误必须逐条额外核对核对参数、请求与响应确保参数、请求体、响应对象正确与 Java 端点对齐operationId应尽可能贴近 DTO 包中对应的 Java 方法对照*RestService.java与*Resource.java接口如 engine-rest/engine-rest/src/main/java 下的实现客户端对比可将构建阶段生成的客户端与真实 REST API 对比多数情况下两者应该高度相似。十一、从模板到可发布产物的闭环综合来看camunda-engine-rest-openapi模块形成了一条完整的文档即代码闭环贡献者按规范在paths、models、lib/commons中编写/修改 FreeMarker 模板mvn clean install时TemplateParser基于目录结构自动推导端点路径与模型清单渲染出openapi.jsonSchemaValidator用 OpenAPI 3.0 官方 schema 本地副本校验结构合法性非法即构建失败openapi-generator-maven-plugin依据 openapi.json 生成 Java Client 源码WireMock JUnit 冒烟测试验证客户端行为DeploymentTest、ProcessInstanceTest、BasicAuthenticationTest等生成的 openapi.json 同时作为模块资源build-helper-maven-plugin将其加入资源目录随制品发布供下游工具消费。这一体系的价值在于REST API 文档不再是与实现脱节的静态文件而是与端点源码、DTO 结构严格对齐、且每轮构建都被机器验证的活文档。对于需要为 Camunda Platform 扩展自定义 REST 端点、或希望理解大型项目如何用模板化方式维护 OpenAPI 规范的开发者engine-rest/engine-rest-openapi是一份极具参考价值的实现样本——其模板组织方式、宏抽象粒度、公共片段复用策略与生成—校验—生成客户端—冒烟测试的构建编排都可以直接迁移到同类项目中复用。【免费下载链接】camunda-bpm-platformCamunda 7 CE is End of Life (EoL). Please check out Camunda 8 instead (https://github.com/camunda/camunda) or read about Camunda 7 Enterprise End of Life (https://camunda.com/blog/2025/02/camunda-7-enterprise-end-of-life-extension/) – Camunda 7 CE was a flexible framework for workflow and decision automation using BPMN and DMN.项目地址: https://gitcode.com/GitHub_Trending/ca/camunda-bpm-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表