-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Apply schema transformers on properties and other subschemas #56709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few comments/questions that I hope are helpful.
Posting a response to all the comments here since they all relate to the same concept: the constraint associated with this implementation that we only apply transformations to subschemas that we can resolve a
If a user sets one of these subschemas explicitly in their own transformer, we have no way of constructing a complete context object for it because we don't know the type associated with the schema.
There's two approaches to solving this: We could relax the constraints on the Alternatively, we could set the So, stuck between a rock and a hard place, I opted not to recurse into these as part of the default implementation. If a user explicitly needs it though, it should be possible to construct their own schema transformer implementation that supports the recursion into these properties and they can initialize the Let me know if you have any other questions or if there is some other way to solve the ambigous context problem. |
Bump for reviews! Hoping to get this in before Friday... |
FWIW I had a look at it last week and didn't spot anything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My only worry is the implicit relationship between schema
properties and jsonTypeInfo
. Any sensible bounds checking we can add?
{ | ||
var derivedJsonTypeInfo = _jsonSerializerOptions.GetTypeInfo(derivedType.DerivedType); | ||
context.UpdateJsonTypeInfo(derivedJsonTypeInfo, null); | ||
await InnerApplySchemaTransformersAsync(schema.AnyOf[anyOfIndex], derivedJsonTypeInfo, context, transformer, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
schema.AnyOf[anyOfIndex]
I don't see any bounds checking here. If it's done earlier, it's far from this callsite and doesn't feel safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this takes an assumption on the implementation details of the schema generator which generates the anyOf child schemas based on the ordering in JsonTypeInfo.DerivedTypes
. I added a check here but things will get spooky for people if they are inserting subschemas into anyOf
that don't match what is understood by STJ from the derived type attributes.
foreach (var propertyInfo in jsonTypeInfo.Properties) | ||
{ | ||
context.UpdateJsonTypeInfo(_jsonSerializerOptions.GetTypeInfo(propertyInfo.PropertyType), propertyInfo); | ||
await InnerApplySchemaTransformersAsync(schema.Properties[propertyInfo.Name], jsonTypeInfo, context, transformer, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same kind of deal, it seems like there is an implicit very close relationship between schema
and jsonTypeInfo
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I introduced a check here to only apply transformers on properties with matching names. This does mean that there is a gap for scenarios where a user applies a schema transformer that changes the casing/format of property keys in a way to is inconsistent with how System.Text.Json is configured. In that case, they'd have to fallback to applying the recursion manually themselves in a top-level schema transformer since this would no-op.
c44268b
to
c525ccd
Compare
Closes #56584.
Schema transformers are currently only called on schemas that are generated at the top-level for respones, parameters, and request bodies. This PR allows schema transformers to be applied recursively into sub-schemas that might appear in these arguments (for example, the schema for an
int
property that is part of aTodo
type). We currently apply transformations to subschema types where we understand how to resolveTypeInfo
for them:schema.items
: for schemas that represent lists of elementsschema.anyOf
: for schemas that represent polymorphic schemas with subtypesschema.properties
: for schemas associated with properties in a typeChanges in this PR include:
OpenApiSchemaTransformerContext.Type
property and addingOpenApiSchemaTransformerContext.JsonTypeInfo
andOpenApiSchemaTransformerContext.JsonPropertyInfo
OpenApiSchemaService
to support applying schemas recursively into the subschemas mentioned aboveSchemaTransformerTests
to cover relevant scenariosNote: One of the new tests introduced here (
SchemaTransformer_CanModifyListOfPolymorphicTypes
) is currently skipped because of a bug I discovered inApplyPolymorphismOptions
where we don't handle things correctly if a polymorphic type is a child of another type (likeList<Shape>
or a type with aShape
property) because of the context.Path.Length == 0 check we currently use to check for base types. This should be resolved once we have can consume dotnet/runtime#104046 in an upcoming runtime update.Another note: I'm hoping to bring these changes in to #56599 for more complete perf coverage for these transformer types.