OpenAPI
Wow OpenAPI 模块提供了基于 OpenAPI 规范的 API 接口。
安装
implementation("me.ahoo.wow:wow-openapi")implementation 'me.ahoo.wow:wow-openapi'
<dependency>
<groupId>me.ahoo.wow</groupId>
<artifactId>wow-openapi</artifactId>
<version>${wow.version}</version>
</dependency>Swagger-UI
Swagger-UI 是一个基于 OpenAPI 规范的 API 文档工具,可以通过 Swagger-UI 来查看和测试 API 接口。

聚合资源归属
一个聚合根资源可以归属于租户、空间和拥有者中的一种或多种。
RESTful URL PATH Spec
[tenant/{tenantId}]/[owner/{ownerId}]/resource/[{resourceId}]/action
租户资源
当聚合根为租户资源时(未标记静态租户ID),自动生成的 RESTful API 会添加 tenant/{tenantId} 路径前缀。
空间资源
当聚合根为空间资源时,自动生成的 RESTful API 会添加 Wow-Space-Id 请求头参数。
拥有者资源
当聚合根被标记为拥有者资源时,自动生成的 RESTful API 会添加 owner/{ownerId} 路径前缀。
@AggregateRoot
@AggregateRoute(owner = AggregateRoute.Owner.ALWAYS)
class Order(private val state: OrderState)当聚合根 ID 与拥有者 ID 相同时,自动生成的 RESTful API 会将 {resourceId} 路径参数移除。比如用户购物车ID即是用户ID时:
@StaticTenantId
@AggregateRoot
@AggregateRoute(owner = AggregateRoute.Owner.AGGREGATE_ID)
class Cart(private val state: CartState)全局路由
获取 Wow 元数据
该路由提供了通过 RESTful API 获取 Wow 编译时元数据的能力,以便验证 Wow 元数据(WowMetadata) 定义的正确性。
curl -X 'GET' \
'http://localhost:8080/wow/metadata' \
-H 'accept: application/json'{
"contexts": {
"example-service": {
"alias": "example",
"scopes": [
"me.ahoo.wow.example.server",
"me.ahoo.wow.example.domain",
"me.ahoo.wow.example.api"
],
"aggregates": {
"cart": {
"scopes": [
"me.ahoo.wow.example.api.cart"
],
"type": "me.ahoo.wow.example.domain.cart.Cart",
"tenantId": "(0)",
"id": null,
"commands": [
"me.ahoo.wow.example.api.cart.ChangeQuantity",
"me.ahoo.wow.example.api.cart.RemoveCartItem",
"me.ahoo.wow.example.api.cart.AddCartItem"
],
"events": [
"me.ahoo.wow.example.api.cart.CartItemAdded",
"me.ahoo.wow.example.api.cart.CartQuantityChanged",
"me.ahoo.wow.example.api.cart.CartItemRemoved"
]
},
"order": {
"scopes": [
"me.ahoo.wow.example.api.order"
],
"type": "me.ahoo.wow.example.domain.order.Order",
"tenantId": null,
"id": null,
"commands": [
"me.ahoo.wow.example.api.order.ChangeAddress",
"me.ahoo.wow.example.api.order.ShipOrder",
"me.ahoo.wow.example.api.order.PayOrder",
"me.ahoo.wow.example.api.order.ReceiptOrder",
"me.ahoo.wow.example.api.order.CreateOrder"
],
"events": [
"me.ahoo.wow.example.api.order.OrderShipped",
"me.ahoo.wow.example.api.order.OrderCreated",
"me.ahoo.wow.example.api.order.AddressChanged",
"me.ahoo.wow.example.api.order.OrderReceived",
"me.ahoo.wow.example.api.order.OrderPaid"
]
}
}
},
"compensation-service": {
"alias": "compensation",
"scopes": [
"me.ahoo.wow.compensation"
],
"aggregates": {
"execution_failed": {
"scopes": [
"me.ahoo.wow.compensation.api"
],
"type": null,
"tenantId": "(0)",
"id": null,
"commands": [],
"events": []
}
}
}
}
}生成 BI 同步脚本
POST /wow/bi/script 生成当前本地聚合的 ClickHouse 同步与展开 SQL。该路由及 OpenAPI operation 默认注册;配置 wow.bi.script.enabled=false 会同时移除二者。启用本身不会增加鉴权,因此必须由应用安全策略保护该管理端点。端点要求提供 application/json 请求体。OpenAPI schema 除部署覆盖字段外还包含 operation 与 replayFromEarliestConfirmed,不再包含 previousManifest;嵌套集群字段只包含 name 和 installation。schema 同时列出枚举值 DEPLOY / RESET、CLUSTER / STANDALONE 与 FAIL / RAW_JSON。请求可以降低 maxExpansionDepth,但不能超过服务端配置值;该配置是端点的安全上限。
服务端配置和每个非 null 请求 override 使用相同的最大长度:database 128 个字符、consumerDatabase 128、timezone 64、topicPrefix 128、kafkaBootstrapServers 4096,topology.cluster.name 与 topology.cluster.installation 各 128。长度恰好等于限制的值可被接受;更长的服务端值会使应用启动失败,更长的 override 返回 400。
| 状态 | Content-Type | 响应体 |
|---|---|---|
200 | application/sql | 仅 SQL 文本;Wow-BI-Diagnostic-Count 给出响应体未携带的诊断数量 |
200 | application/json | SQL、destructive 标记与诊断;Wow-BI-Diagnostic-Count 给出相同的诊断数量 |
400 | 错误响应 | 空或无效 JSON 请求体、超过长度限制的 override、其他无效选项值或无效拓扑组合 |
406 | 错误响应 | 请求的表示均不受支持,或所有受支持的表示均设为 q=0;运行时 Wow-Error-Code 为 NotAcceptable |
415 | 公共 wow.UnsupportedMediaType response | 缺少或不支持的请求 Content-Type;运行时 Wow-Error-Code 为 UnsupportedMediaType |
500 | 错误响应 | 未预期的 BI 脚本生成失败 |
502 | 错误响应 | inspected replica 上的 owned ClickHouse catalog 不一致 |
503 | 错误响应 | ClickHouse catalog inspection 不可用 |
504 | 错误响应 | ClickHouse catalog inspection 超时 |
{} 使用服务端选项执行 DEPLOY,调用方无需保存部署历史。默认 NoOp inspector 会返回未对账诊断;注册 ClickHouse inspector 后从 catalog 恢复历史。RESET 需要 replayFromEarliestConfirmed=true,即使聚合作用域为空也要求服务端配置 consumerGroupNamespace,且 inspector 必须可用,否则返回 400。提供 topology 时必须提供 topology.mode。在 CLUSTER 模式下,省略的集群字段继承当前集群服务端基础配置;如果服务端基础配置是独立模式,则继承领域集群默认值。STANDALONE 拒绝 cluster 对象。DEPLOY 与 RESET 不迁移数据库、consumer-group namespace 或 ClickHouse 拓扑;部署新范围前必须先停止并清理旧物理范围。旧版 GET 方法在该路径上没有路由并返回 404。
curl -X POST 'http://localhost:8080/wow/bi/script' \
-H 'content-type: application/json' \
-H 'accept: application/sql' \
--data '{}'{
"database": "analytics",
"topology": {
"mode": "STANDALONE"
}
}{
"topology": {
"mode": "CLUSTER",
"cluster": {
"name": "production"
}
},
"kafkaBootstrapServers": "kafka:9092",
"topicPrefix": "analytics."
}HTTP/1.1 200 OK
Content-Type: application/sql
Wow-BI-Diagnostic-Count: 0
-- global --
CREATE DATABASE IF NOT EXISTS "bi_db" ON CLUSTER '{cluster}';
CREATE DATABASE IF NOT EXISTS "bi_db_consumer" ON CLUSTER '{cluster}';当前展开 schema、结构化类型、原始值语义和无损标量映射参见商业智能;路由配置与 Kafka/topic 优先级参见BI 脚本配置。
生成全局 ID
该路由提供了通过 RESTful API 生成全局ID的能力。
curl -X 'GET' \
'http://localhost:8080/wow/id/global' \
-H 'accept: text/plain'0U2MNGBQ0001001