OpenApi: optional query and header parameters are documented as nullable
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 57/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- api
調査の方向性
Start in OpenApi.ts at processParameters, the entry point named in the issue, and trace how optional query and header parameter schemas pass through the representation pipeline. Compare those parameter schemas with the body handling described in the issue, then inspect or add focused tests for OpenApi.fromApi query and header output. Done means optional parameters omit JSON null while preserving the documented string forms, with body behavior unchanged.
索引モデルが issue の本文から書いたものです。
説明
What version of Effect is running?
4.0.5. Also seen on 4.0.0. OpenApi.ts on main is the same as in 4.0.5.
What steps can reproduce the bug?
OpenApi.fromApi documents a query parameter declared with Schema.optional as anyOf: [T, null]. A query string has no way to send null, and the server's query decoder doesn't accept one.
import { Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api"
const Query = Schema.Struct({
limit: Schema.optional(Schema.FiniteFromString),
cursor: Schema.optional(Schema.NullOr(Schema.String))
})
const Api = HttpApi.make("api").add(
HttpApiGroup.make("items").add(
HttpApiEndpoint.get("list", "/items", { query: Query, success: Schema.String })
)
)
console.log(JSON.stringify(OpenApi.fromApi(Api).paths["/items"].get.parameters, null, 2))
// What the server does with the `null` the document allows
const decodeQuery = Schema.decodeUnknownExit(Schema.toCodecStringTree(Query))
console.log(decodeQuery({ limit: "null" })._tag) // "Failure"
What is the expected behavior?
limit documented as { "type": "string" } with required: false. required: false already says the parameter can be left out, so the undefined that Schema.optional adds has nothing left to describe.
cursor documented with only the string form of its NullOr, anyOf: [{ "type": "string", "enum": ["null"] }, { "type": "string" }], and no JSON null around it.
What do you see instead?
[
{
"name": "limit",
"in": "query",
"schema": { "anyOf": [{ "type": "string" }, { "type": "null" }] },
"required": false
},
{
"name": "cursor",
"in": "query",
"schema": {
"anyOf": [
{ "anyOf": [{ "type": "string", "enum": ["null"] }, { "type": "string" }] },
{ "type": "null" }
]
},
"required": false
}
]
cursor shows the mismatch most clearly. Its NullOr gets the query codec's representation, the string "null". The undefined from Schema.optional gets the JSON codec's, where Undefined encodes as null. One parameter ends up described by two codecs.
Additional information
- Headers have the same problem:
headers: Schema.Struct({ "x-trace": Schema.optional(Schema.String) })comes out asanyOf: [{ "type": "string" }, { "type": "null" }]. - Bodies are fine. A JSON body does decode
nulltoundefined, soT | nullis the right description there. - Effect's own
HttpApiClientis unaffected, since it dropsundefinedbefore building the URL. Clients generated from the document are the ones that break. We generate ours with orval, which typeslimitasstring | nulland sends?limit=nullwhen givennull. The service then rejects the request, or, for a plainSchema.String, reads"null"as a real value. - Switching to
Schema.optionalKeyfixes the document. It also makes{ limit: undefined }fail to encode, so every caller that builds a query from a possibly-undefined value has to leave the key out by hand, which is whatSchema.optionalexists to avoid. - A possible workaround until it's fixed: an
OpenApi.Transformthat drops thenullmember from every parameter whererequiredisfalse. - My guess at the cause, from reading the source:
processParametersqueues parameter schemas as"properties"ops, and those go through the same representation pipeline as bodies, so an optional property'sundefinedgets the JSON rule.
- 主要言語
- TypeScript
- スター
- 16.7k
- フォーク
- 808
- 平均マージ
- 10時間 7分
- マージ済み PR(30日)
- 808
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Effect-TS/effect のほかの issue
-
Support {self: this} for fnUntraced対応中かも @ArjunCodess が 32 日前に担当しました。 オープンenhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
Effect-TS/effect#8101 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
v4 Cache.get: a caller that joins an abandoned lookup fails with an interruption it did not ask forオープン
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 1 日以内に返信
-
Typed unix socket and TLS options for `BunHttpClient` and `DenoHttpClient`対応中かも @effect-bot が今日担当しました。 オープンdocker-made-me-do-it enhancement platform
Effect-TS/effect#9687 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
RFC 9457 Problem Details for HttpApi errors対応中かも @effect-bot が今日担当しました。 オープンdocker-made-me-do-it enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 20/100
メンテナーはふだん 1 日以内に返信
Effect-TS/effect の issue をすべて見る
似ている issue
-
ready-for-agent
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
xavxyz/bei-shan-lin-shui#57 ·
メンテナーはふだん 1 日以内に返信
-
[BUG] rag: sentence content can cross the reported sentence boundaries対応中かも @LJK-ikun が今日担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
bug needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
README: the Resource URI Schemas example's file://documents/* pattern only matches that literal URIオープン
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
platformatic/mcp#361 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
siyuan-note/siyuan#20799 · コメント 7 件 ·
メンテナーはふだん 1 日以内に返信