Skip to content

fix(swagger): align api-tools proxy schemas with actual responses#52

Open
torrid-fish wants to merge 4 commits into
feat/api-toolsfrom
fix/swagger-api-tools-schemas
Open

fix(swagger): align api-tools proxy schemas with actual responses#52
torrid-fish wants to merge 4 commits into
feat/api-toolsfrom
fix/swagger-api-tools-schemas

Conversation

@torrid-fish

Copy link
Copy Markdown
Member

目的

Swagger UI 上 /v1/mark-accent/stream 的 Example Value 只顯示一個字面 "string",跟實際 NDJSON 完全對不起來(#50)。順手把其他 api-tools proxy 路由幾個會誤導使用者的 schema 雷一起修掉。

方法/實作說明

  • 主要修改:

    • internal/api/api_tools.go:handler annotations(@Success / @Failure / @Description
    • internal/api/api_tools_models.go:新增 MarkAccentStreamChunk / ProxyErrorResponse,調整 APIToolsErrorWordAccentSubword,清理 dead description tags
    • docs/swagger/{docs.go,swagger.json,swagger.yaml}make swag 重新產生
  • 關鍵實作:

    • Stream chunk 真實 shape@Success 200 {string} string{object} MarkAccentStreamChunk,包含 {chunk, subchunk, status, result, error} 五個 top-level 欄位(對照實際 payload 確認)。
    • 502 不再是泛型 map:新增 ProxyErrorResponse { error string },與 proxyToErrorHandler 實際輸出 {"error": "Failed to contact external API"} 對齊;7 個 handler 的 @Failure 502 全部換掉。
    • APIToolsError 嵌入時的 example:原本是 code:500 / message:"HTTP error 500",在 200 success response 的合成 example 裡造成 status:200error.code:500 的矛盾畫面。改成 code:0 / message:" "(swag 不接受空字串,會 fallback 成字面 "string",所以用單空白)。
    • 遞迴 subwordWordAccentSubword.Subword(自我引用 []WordAccentSubword)標 swaggerignore:"true",因為 swag 把 self-referential type 渲染成 ["string"];該欄位 description 本就是「reserved for compatibility; typically empty」,runtime JSON 仍然輸出。
    • error 欄位的 variant 註記:每個 handler 的 @Description 末尾追加 Body convention: the inner status carries the real result code; error is null on success and populated only when status != 200.(swag 在 OpenAPI 2.0 模式下會丟棄 \$ref 欄位上的 sibling description,所以欄位標籤上寫不下,搬到 endpoint description 才看得到)。

關聯 Issue

Closes #50

附註

🤖 Generated with Claude Code

- /v1/mark-accent/stream: replace `@Success 200 {string} string` with a
  proper `MarkAccentStreamChunk` schema so Swagger UI shows the real
  NDJSON line shape instead of a literal "string". Closes #50.
- Add `ProxyErrorResponse` for the 502 body the reverse proxy writes
  (`{"error": "Failed to contact external API"}`). Was `map[string]string`,
  which Swagger UI rendered as a generic `additionalProp*: string` map.
- Tidy `APIToolsError` embedded examples so a successful response's
  `error` field renders as `{code:0, message:" "}` instead of the
  alarming literal `{code:500, message:"HTTP error 500"}` that swag was
  compositing into otherwise-200 examples.
- `swaggerignore` the recursive `WordAccentSubword.Subword` field — swag
  renders self-referential types as `["string"]`; the field is "reserved
  for compatibility; typically empty" in real responses anyway.
- Append a `Body convention:` sentence to every api-tools handler's
  `@Description` explaining that the body's `status` field carries the
  real result code and `error` is `null` on success. swag drops
  `description:` siblings of `$ref`, so the field-level convention had
  nowhere else to land.

Closes #50
chatgpt-codex-connector[bot]

This comment was marked as resolved.

Per-endpoint exceptions are delivered inside the body as `{status: 5xx,
result: null, error: {...}}` (api-tools follows JSON-RPC 2.0 over HTTP).
The previous schema declared `result` as a non-null array/object, so
OpenAPI codegen producing strict client types (TypeScript, Java, Kotlin)
would reject or NPE on valid failed responses instead of surfacing the
embedded `error`.

Tag every `result` field with `extensions:"x-nullable=true"`. For pointer
fields (`*IdDetails`, `*SentenceQueryWordResult`) swag emits an `allOf`
wrapper so the `x-nullable` extension can sit alongside the `$ref`. Also
covers the streaming endpoint flagged by codex on PR #52 — same body
convention applies to every chunk.

Refs #52 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant