Conversation
`schemars` only applies the transforms from its settings inside `root_schema_for` and `take_definitions(true)`. `aide` calls neither when building operations: it uses `subschema_for` and reads schemas back via `GenContext::resolve_schema`, so every schema `aide` inlines into the document was emitted untransformed and the generator settings were silently ignored. This is not limited to custom settings. `aide` defaults to `SchemaSettings::draft07`, which ships `ReplaceUnevaluatedProperties`, `RemoveRefSiblings` and `ReplacePrefixItems`, so a query struct with a tuple field emitted draft 2020-12 `prefixItems` into a draft 7 document. Add `GenContext::resolve_schema_transformed` and `GenContext::apply_transforms`, and use them wherever a resolved or inline schema is embedded directly: `parameters_from_schema` (which covers `Path`, `Query`, typed routing and `serde_qs`), the request body and response media types for `Json` and both `Form` extractors, and the header schema for `TypedHeader`. Schema references are deliberately left alone, since the definitions they point at are already transformed by `take_definitions(true)` when they are merged into the document. `TypedPath` needs care in the other direction: it reads its description out of `root_schema_for`, which has already run the transforms, so reusing that schema for the parameters would transform them twice. `Transform` carries no idempotency guarantee, so it now takes the parameters from `subschema_for` like every other caller of `parameters_from_schema`. Supersedes tamasfe#230, which fixed `parameters_from_schema` but whose `operation_input_json` hunk transformed a clone that was only read for its description and then discarded, and which left the other five sites untouched. Co-authored-by: Diggory Blake <diggsey@googlemail.com>
MOZGIII
approved these changes
Sep 1, 2026
MOZGIII
left a comment
There was a problem hiding this comment.
I've glanced though this, and although I have nothing to do with this PR or project - the patch looks good to me
Collaborator
|
I'll try to get to this soon! |
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.
Supersedes #230, part of #270.
As @Diggsey made the original report and analysis, I made him co-author on the commit.
Intent
aide never applies its schemars settings to the schemas it inlines.
schemars runs the transforms from
SchemaSettingsin two places,root_schema_forandtake_definitions(true), and aide uses neither when building an operation. It callssubschema_for::<T>()and reads the result back throughGenContext::resolve_schema, which is a plain lookup. Nothing on that path transforms anything. (Diggsey's description on #230.)You don't need custom settings to hit this. aide's own generator is built from
SchemaSettings::draft07(), which already shipsReplacePrefixItemsand friends, so aQuery<T>overemits
prefixItemsinto a document that announces draft 7. Validators ignore keywords they don't know, so that parameter accepts any array at all. Definitions under#/components/schemaswere always fine sincemerge_api_withcollects them withtake_definitions(true); only the inlined half was wrong.Proposed Changes
GenContextgetsresolve_schema_transformed(resolve a ref, return a transformed copy) andapply_transforms(transform in place). Every site that embeds a generated schema now uses one:parameters_from_schema, the media types forJsonand bothForms, andTypedHeader.apply_transformsskips$refs on purpose. They have to stay references, and their targets get transformed at merge time. That's also what makes one path work under bothextract_schemasmodes.TypedPathhad the reverse problem. It reads its description fromroot_schema_for, which does transform, then reused that schema for the parameters, so they'd now be transformed twice.Transformpromises nothing about idempotency, so it takes parameters fromsubschema_forlike every other caller.Two differences from #230. Its
parameters_from_schemachange is here as-is. Itsaxum/inputs.rschange isn't: at that site the resolved schema is only read for.get("description")while theMediaTypegets the untouchedjson_schema, so the transformed clone was discarded two lines later. I transformed the schema that actually gets embedded instead. That same shape turned up in five more places #230 missed (bothForminputs, bothoperation_responseimpls,TypedHeader), all fixed here.Breaking Changes
None to the API, both methods are additive. Tested on both schemars 1.0.4 and 1.2.2.