Conversation
A path response that `$ref`s a component response compiled to
`{ [k: string]: unknown }`: `buildContentTypesFromReferenceObject` handed
`ResponseContent` a `JSONSchema` _model instance_ where a raw schema object
was expected, so the instance was wrapped in a second `JSONSchema` and
`json-schema-to-typescript` had nothing to work with. It now passes
`asCustomTypeRef()`, which references the component response's own generated
content type instead of rebuilding it -- the same indirection the path-level
request body already uses, and the only option that does not duplicate an
inline component response at every referencing path.
Every error response in the mittwald spec is such a `$ref`, so this left every
error payload in the published client untyped. Regenerating turns 3896 index
signatures across v2 and v3-next into references to
`Components.Responses.Commons*Error.ApplicationJson`; consumers doing
`assertStatus(response, 400)` now get real fields. The generated diff contains
nothing else -- regenerating the unmodified base produces no diff at all.
`RequestBodies` had the same symptom from a different cause: a request body
component is a `RequestBodyObject`, not a schema, so compiling the wrapper
(`content`, `required: true`) also yielded an index signature. The schema is
now unwrapped from `content[mediaType].schema`, preferring `application/json`
because a component produces a single type and cannot name one per media
type. The mittwald spec declares no request body components, so this only
shows up in the fixture.
The two tests that pinned the old behaviour now assert the resolved types.
The second one is replaced by a blanket assertion that no type in the fixture
compiles to an index signature, which guards the class of bug rather than the
two known instances.
Not addressed here: `Paths.V2Files.Post.Parameters.RequestBody` is still
untyped, because `RequestParameters.fromDoc` only looks at
`content["application/json"]` and `POST /v2/files` declares only
`multipart/form-data`. That is the subject of #300.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…response-body-types The base branch picked up master, which regenerated the committed client; both sides had therefore rewritten the generated types. Resolved by taking the base branch's client and regenerating it with this branch's generator fix, so the $ref'd response and request body types resolve again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #306, which added the tests that pin down the old behaviour. Base this on #306, not
master— it will need retargeting once #306 lands.The bug
A path response that
$refs a component response compiled to an index signature:ResponseContentTypes.buildContentTypesFromReferenceObjecthandedResponseContentaJSONSchemamodel instance where a raw schema object was expected. The instance got wrapped in a secondJSONSchema, soschemaObjectwas a model instance rather than a schema andjson-schema-to-typescriptfell back to its index-signature default.Every error response in the mittwald spec is such a
$ref:so every error payload in the published
@mittwald/api-clientwas untyped — even thoughComponents.Responses.CommonsValidationError.ApplicationJsonwas generated correctly right next to it. Consumers callingassertStatus(response, 400)gotunknownfields.The fix
asCustomTypeRef(), notschemaObject. Both cure the index signature, butasCustomTypeRef()emits a reference to the already-generated component type:schemaObjectwould instead inline the component's underlying schema. That only works at all when the component response's schema is itself a\$ref, and where it does work it duplicates the schema at every referencing path — ~4000 copies here. Referencing the component also matches how the path-level request body already resolves (RequestBody = Components.RequestBodies.PetBody), and is exactly the output the old test'snot.toContainpredicted.RequestBodieshad the same symptom from a different cause: a request body component is aRequestBodyObject, not a schema — the schema sits undercontent[mediaType].schema— so the whole wrapper (content,required: true) was being compiled. It is now unwrapped, preferringapplication/jsonsince a component yields a single type and cannot name one per media type. The mittwald spec declares no request body components, so this half only shows up in the fixture.Tests
Both tests now assert the resolved types. The second one is replaced by a blanket
not.toContain("[k: string]: unknown;")— nothing in the fixture should compile to an index signature, which guards the whole class of bug rather than the two known instances.Regenerated client
I regenerated on the unmodified base first to prove it was clean (empty diff), so the diff here is purely this change:
Every changed line is the same substitution. 3896 index signatures across the two clients became typed references:
Commons*DefaultErrorCommons*RateLimitErrorCommons*ValidationErrorCommons*NotFoundErrorSslValidationError,DomainSuccessResponse, …)Note this is a type-level widening from
unknownto concrete fields, so it can surface pre-existing type errors in consumer code that was previously indexing these payloads freely.Not addressed here
Paths.V2Files.Post.Parameters.RequestBodyis still an index signature, for an unrelated reason:RequestParameters.fromDoclooks only atcontent["application/json"], andPOST /v2/filesdeclares onlymultipart/form-data, so it falls through to the rawRequestBodyObject. That is the subject of #300, so I left it rather than collide. The 6 remaining index signatures are genuine free-form schemas in the spec (expiresAt: {}, audit-logchanges).Verification
@mittwald/api-code-generator:test:unit— 145/145 passnx run-many -t test:unit— all passnx run-many -t test:compile --parallel=3 --skip-nx-cache— all passnx run-many -t lint— cleantest:client-generation-cleanis onlygit diff --exit-codeand proves nothing about generation, so the generated output was verified by regenerating and reading the diff.🤖 Generated with Claude Code