diff --git a/.changeset/fix-platform-flat-anyof-union-payload.md b/.changeset/fix-platform-flat-anyof-union-payload.md new file mode 100644 index 00000000000..7416144aee1 --- /dev/null +++ b/.changeset/fix-platform-flat-anyof-union-payload.md @@ -0,0 +1,5 @@ +--- +"@effect/platform": patch +--- + +`OpenApi.fromApi` now emits a flat `anyOf` array when multiple union members in `setPayload` share the same content type. Previously, each additional member was wrapped in a new `Union` node, producing deeply nested `anyOf: [ anyOf: [A, B], C ]` structures. The fix uses `HttpApiSchema.UnionUnifyAST` — already used by the response-map accumulator — to flatten unions as they are collected. diff --git a/packages/platform/src/HttpApi.ts b/packages/platform/src/HttpApi.ts index 2cbcf250648..c7f981d3d2d 100644 --- a/packages/platform/src/HttpApi.ts +++ b/packages/platform/src/HttpApi.ts @@ -419,7 +419,7 @@ const extractPayloads = (topAst: AST.AST): ReadonlyMap { expectSpecPaths(api, expected) }) }) + + it("setPayload with a flat JSON union produces flat anyOf (not nested)", () => { + const A = Schema.Struct({ _tag: Schema.Literal("A"), a: Schema.String }) + const B = Schema.Struct({ _tag: Schema.Literal("B"), b: Schema.Number }) + const C = Schema.Struct({ _tag: Schema.Literal("C"), c: Schema.Boolean }) + const api = HttpApi.make("api").add( + HttpApiGroup.make("group").add( + HttpApiEndpoint.post("post", "/") + .addSuccess(Schema.String) + .setPayload(Schema.Union(A, B, C)) + ) + ) + expectSpecPaths(api, { + "/": { + "post": { + "tags": ["group"], + "operationId": "group.post", + "parameters": [], + "security": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "required": ["_tag", "a"], + "properties": { + "_tag": { "enum": ["A"], "type": "string" }, + "a": { "type": "string" } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["_tag", "b"], + "properties": { + "_tag": { "enum": ["B"], "type": "string" }, + "b": { "type": "number" } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["_tag", "c"], + "properties": { + "_tag": { "enum": ["C"], "type": "string" }, + "c": { "type": "boolean" } + }, + "additionalProperties": false + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "a string", + "content": { + "application/json": { + "schema": { "type": "string" } + } + } + }, + "400": HttpApiDecodeError + } + } + } + }) + }) }) describe("HttpApiEndpoint.del", () => {