Open captainsafia opened 1 month ago
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis See info in area-owners.md if you want to be subscribed.
This gap has presented a blocker
@captainsafia, as in we need to address this in .NET 9?
@captainsafia, as in we need to address this in .NET 9?
Ah, should've been clearer about this.
Not a blocker for .NET 9, but definitely would be good to slot in for .NET 10.
public interface IJsonSchemaResolver { JsonSchema GetJsonSchema(JsonTypeInfo typeInfo); JsonSchema GetJsonSchema(JsonPropertyInfo propertyInfo); }
There is no JsonSchema
type shipping with .Net 9, and I'm not aware of one planned for 10. The current implementation for generation simply generates a JsonNode
.
The problem with the proposed API is JSON schemas exist in the context of a document.
For example, schemas in a document reference each other via $ref
, and schemas are commonly stored together in $defs
(I don't know if JsonSchemaMapper has a feature to output generated schemas together in $defs
yet. If you don't, I guarantee that there will be a lot of people asking for this feature. It's the idiomatic way to organize schemas in JSON schema).
These things happen beyond the scope of an individual JsonSchema
instance. Customizations to schema generation for a JsonTypeInfo
need to flow out and impact the rest of the document. If JsonTypeInfo
needs to generate its own subschemas based on types in its properties, people will want:
$defs
Person
type, to all reference the common schema in $defs
with $ref
.I think customization must happen before the document is generated and work at the Type
level. Swashbuckle does this successfully using ISerializerDataContractResolver
.
Using Swashbuckle's contract resolver, I can instruct it what the schema output for a type should be at the Type
level. For example:
The Any
type has a JsonConverter that customizes its output. I can then make its schema match the custom output by saying its schema is an object, with one known property of System.String
, and additional properties of type Google.Protobuf.Value
. The Swashbuckle schema generated then uses this custom contract to generate the desired JSON schema. Google.Protobuf.Value
. is stored in the idiomatic shared location, and other places in the doc that also use Google.Protobuf.Value
have a $ref
to that shared location.
The current implementation does not support $ref
s, despite my arguing for them (see comments in the relevant PRs). What is currently provided is a stepping stone; just enough to get asp.net over the line.
Yes, what JsonSchemaMapper
currently does is very rudimentary in .NET 9.
$ref and $def are needed. They're the idiomatic way to organize schemas in JSON. Without those features, a large amount of work is required to make good output from the type.
As evidence of this, see everything that ASP.NET Core needs to do to post-process the output of the mapper to make it usable. The mapper should be the one doing the work to place schemas in definitions and reference them. Some post-processing in ASP.NET Core will still be required to modify the JSON schema syntax to be compatible with OpenAPI, but it will be much less, and simpler, than what is currently done.
As soon as you start adding support for these features, you realize that an API to customize schemas individually doesn't work.
For context, the reason why such an API wasn't added in .NET 9 is due to the lack of a built-in JsonSchema
type. Building these abstractions around JsonNode
is plainly not a good idea in the long run. Once a JsonSchema
type is available building this feature should be relatively straightforward.
JsonSchemaExporter
currently does not use $def
(or $id
) OOTB in the schemas that it generates. $ref
schemas using JSON pointer are only generated in case of recursive schemas. The reason is naming: for a general-purpose naming scheme we would need to use identifiers that either encode the FQN of a given type or generate UUIDs neither of which felt like an acceptable solution. If we do add support for $def
or $id
in the future this should involve exposing an abstraction for users to define their own naming scheme.
The current implementation of the
JsonSchemaExporter
generates schemas for types based on its on semantics. There's currently not strategy for types/converters to advertise their associated JSON schemas.This gap has presented a blocker for a couple of scenarios in ASP.NET Core's OpenAPI support around JSON schema.
true
schema.While both System.Text.Json and ASP.NET Core expose APIs for modifying schemas at different layers of the stack, both approaches are reactive and allow mutating the schema that is generated instead of proactively dictating the schema that should be set.
Solutions that have been discussed in the past includ exposing a new
IJsonSchemaResolver
interface for type owners to implement:Or alternatively including a new virtual method on the JsonConverter to define associated schemas:
cc: @JamesNK @eiriktsarpalis