Skip to content

发布出去的 /api/v1/openapi.json 描述的 built-in 路由一条都不存在 —— 10 个 operation 真实 boot 全部 404(证伪 #5456 的「当前未漂移」) #5588

Description

@baozhoutao

发布出去的 GET /api/v1/openapi.json 里,built-in 路由那一段描述的每一条路径都不存在。真实 boot 逐条探测,文档里的路径全部 404;真实路由在另一个前缀上。任何人拿这份文档生成客户端,生成出来的客户端每一个数据调用都会 404。

基线:origin/main @ 5acb93add。在 #5456 的前提复核中量到(#5456 的 body 断言「当前未漂移,7 条与今天的路由面一致」——该断言被本单证伪),按 Prime Directive #10 单独立单。

真实 boot 实测

pnpm dev:crm -- --fresh -p 39177
GET /api/v1/openapi.json  →  200, 151 paths({object} 已按 CRM 对象展开)

逐条探测文档描述的路径 vs 真实路由:

文档里的(展开后)路径                     真实结果
/api/crm_contact                       404   {"error":"Not found"}
/api/meta                              404   {"error":"Not found"}
/api/meta/types                        404   {"error":"Not found"}
/api/.well-known/objectstack           404   {"error":"Not found"}

真实路由                                  结果(401 = 路由在,鉴权挡住)
/api/v1/data/crm_contact               401   {"error":"UNAUTHENTICATED",...}
/api/v1/meta                           401
/api/v1/discovery                      200
/.well-known/objectstack               200   ← dispatcher 在根上服务,不在 /api 下

动词也错。文档写 PUT {object}/{id},真实是 PATCH——服务器对 PUT 明确回 405:

PUT   /api/v1/data/crm_contact/xyz   →  405
PATCH /api/v1/data/crm_contact/xyz   →  401

逐条对照

packages/spec/scripts/build-openapi.tsgenerateCrudPaths / generateMetadataPaths / generateDiscoveryPathsbasePath = '/api' 手写出 7 条 path / 10 个 operation:

base spec operation 真实 rest 路由 判定
GET /api/{object} GET /api/v1/data/:object 路径错(缺 /v1、缺 /data)
POST /api/{object} POST /api/v1/data/:object 路径错
GET /api/{object}/{id} GET /api/v1/data/:object/:id 路径错
PUT /api/{object}/{id} PATCH /api/v1/data/:object/:id 路径错 且动词错(PUT 回 405)
DELETE /api/{object}/{id} DELETE /api/v1/data/:object/:id 路径错
GET /api/meta GET /api/v1/meta 路径错(缺 /v1)
GET /api/meta/types 全仓没有这条路由 描述了一条谁都不服务的路由(最接近的是 GET /api/v1/meta,它返回 types)
GET /api/meta/{type} GET /api/v1/meta/:type 路径错(缺 /v1)
GET /api/meta/{type}/{name} GET /api/v1/meta/:type/:name 路径错(缺 /v1)
GET /api/.well-known/objectstack rest 没有这条路由 dispatcher(packages/runtime/src/dispatcher-plugin.ts:658)在根路径 /.well-known/objectstack 上服务;rest 的 discovery 是 GET /api/v1 + GET /api/v1/discovery

字面比对:0/10 命中。补 /v1/data 之后仍有 3/10 对不上。

反方向同样不等:RestServer.getRoutes() + 两个 direct-mount registrar 枚举出 91 条真实路由;即使只看 base spec 自称覆盖的三个 ledger family(crud 6 + metadata 17 + discovery 2 = 25 条),文档也只描述了 10 个 operation。

为什么没被发现

serve 期的 enrichment(rest-server.ts registerOpenApiEndpoints)只做四件事:覆写 servers[0](只写 origin,不含 basePath)、展开 {object}、合并声明式端点、覆写 info.version没有任何一步重写 path 前缀。而 check:generated 的收尾台账把 gen:openapi 记为无门禁({ gen: 'gen:openapi', why: 'the OpenAPI document is generated but no check gate compares it to the routes' }),#5168 补的是产物自洽门($ref 能解析、schema 不降级),不看路由。所以两边各自「正确」,合起来全错,全绿。

现有测试还把错误形状钉住了:packages/rest/src/rest-openapi-route.test.ts:125 断言 body.paths['/api/{object}']['x-template'] === true —— 它证明了服务出去的文档字面上就带着 /api/{object}

处置需要一次契约裁决(本单不预设)

注意 apiPath可配置的(api.apiPath ?? api.basePath + '/' + api.version,rest-server.ts:2830),所以 packages/spec 里的静态 JSON 原则上无法对所有部署写对前缀——今天写 /api 只是错得更彻底,写死 /api/v1 也只是对默认部署正确。

关联

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions