Skip to content

fix: unions used as a request or response body generate typed instead of any - #36

Merged
giraffesyo merged 1 commit into
canaryfrom
fix/typed-union-bodies
Aug 4, 2026
Merged

fix: unions used as a request or response body generate typed instead of any#36
giraffesyo merged 1 commit into
canaryfrom
fix/typed-union-bodies

Conversation

@giraffesyo

Copy link
Copy Markdown
Member

What

A oneOf/anyOf schema used directly as a request or response body generated any. It now generates the same typed union the generator already produces elsewhere.

The synthesis path existed and worked; it was simply never reached from bodies. synthesizeInlineUnion returns false without a naming hint, and the body path resolved with an empty one:

// operations.go, before
return a.resolveGoType(schema, "")

This threads the operation's Go name down through convertRequestBody, convertResponses, convertSingleResponse, and resolveMediaTypeSchema, so a body union is named <Operation>Body or <Operation>Response.

Titled unions name themselves

Synthesized unions are deduplicated by variant refs and discriminator, so a union shared by several operations is named after whichever one the spec reaches first. That is order-dependent: inserting a route earlier renames existing generated types, which is churn for consumers that diff-gate their SDK.

So a title on the union now wins over the operation hint. A spec that names its unions gets stable names regardless of route order; a spec that does not still improves from any.

Effect on a real spec

Against the Parallel Works API (754 types), before:

func (c *Client) GetClusterAttachedStorages(...) (*[]any, error)
func (c *Client) AttachClusterStorage(..., body any) (*[]any, error)
func (c *Client) GetClusterDefinition(...) (*any, error)

after, with title set on the two attached-storage unions and nothing else changed:

func (c *Client) GetClusterAttachedStorages(...) (*[]AttachedStorage, error)
func (c *Client) AttachClusterStorage(..., body AttachedStorageWrite) (*[]AttachedStorage, error)
func (c *Client) GetClusterDefinition(...) (*GetClusterDefinitionResponse, error)

The generated union carries the discriminator-driven UnmarshalJSON, so decoding yields the concrete variant rather than a map.

Tests

testdata/complex-schemas.yaml gains two paths: one with untitled union bodies, one titled. New tests assert the untitled bodies take the operation hint, that an identical union elsewhere still deduplicates, and that a titled union uses its title and does not also emit a hint-named type. The exact-count assertion in TestComplexSchemas_AllTypesPresent is updated for the three new synthesized types.

Note this changes generated output for any spec with union bodies: those signatures move from any to a named type. That is the point, but it is a visible diff for consumers on regeneration.

@giraffesyo
giraffesyo merged commit a40e2ca into canary Aug 4, 2026
@giraffesyo
giraffesyo deleted the fix/typed-union-bodies branch August 4, 2026 22:35
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