-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
Closed
Copy link
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Text.Json
Milestone
Description
Introduction
This issue defines the JSON schema exporting APIs largely following the design of the stj-schema-mapper prototype. Rather than introducing a JSON schema exchange type, the proposed exporter methods generate schema documents represented as JsonNode
instances which can be modified or mapped to other schema models as required.
The exporter employs a callback model allowing users to enrich the generated schema for every node in the generated type graph using metadata from arbitrary attribute annotations.
Contributes to #100159
API Proposal
namespace System.Text.Json.Schema; // New namespace
public static class JsonSchemaExporter
{
public static JsonNode GetJsonSchemaAsNode(this JsonSerializerOptions options, Type type, JsonSchemaExporterOptions? exporterOptions = null);
public static JsonNode GetJsonSchemaAsNode(this JsonTypeInfo typeInfo, JsonSchemaExporterOptions? exporterOptions = null);
}
public sealed class JsonSchemaExporterOptions
{
/// The default options singleton.
public static JsonSchemaExporterOptions Default { get; } = new();
/// Determines whether schema references should be generated for recurring schema nodes.
public bool AllowSchemaReferences { get; init; } = true;
/// Determines the compatibility mode used by the exporter.
public JsonSchemaExporterCompatibilityMode CompatibilityMode { get; init; } = JsonSchemaExporterCompatibilityMode.Strict;
/// Defines a callback that is invoked for every schema that is generated within the type graph.
public Action<JsonSchemaExporterContext, JsonObject>? OnSchemaNodeGenerated { get; init; }
}
/// Context of the current schema node being generated.
public readonly struct JsonSchemaExporterContext
{
/// The parent collection type if the schema is being generated for a collection element or dictionary value.
public ReadOnlySpan<string> Path { get; }
/// The JsonTypeInfo for the type being processed.
public JsonTypeInfo TypeInfo { get; }
/// The JsonPropertyInfo if the schema is being generated for a property.
public JsonPropertyInfo? PropertyInfo { get; }
}
public enum JsonSchemaExporterCompatibilityMode
{
/// Generates schemas that are strict with respect to nullability annotations and constructor parameter requiredness.
Strict = 0,
/// Generates schemas that are more permissive but preserve compatibility with the specified JsonSerializerOptions.
JsonSerializer = 1,
}
API Usage
Here's an example using the callback API to extract schema information from other attributes:
var options = new JsonSchemaExporterOptions
{
OnSchemaNodeGenerated = static (ctx, schema) =>
{
DescriptionAttribute? descriptionAttribute = ctx.PropertyInfo?.AttributeProvider?
.GetCustomAttribute<DescriptionAttribute>();
if (descriptionAttribute != null)
{
schema["description"] = (JsonNode)descriptionAttribute.Description;
}
}
});
JsonNode node = JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(MyPoco), options);
// { "type" : "object", "properties" : { "X" : { "type" : "integer", "description" : "This is property X" } } }
public class MyPoco
{
[Description("This is property X")]
public int X { get; set; }
}
stephentoub
Metadata
Metadata
Assignees
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Text.Json