Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/OpenApi/sample/Endpoints/MapSchemasEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static IEndpointRouteBuilder MapSchemasEndpoints(this IEndpointRouteBuild
schemas.MapPost("/child", (ChildObject child) => Results.Ok(child));
schemas.MapPatch("/json-patch", (JsonPatchDocument patchDoc) => Results.NoContent());
schemas.MapPatch("/json-patch-generic", (JsonPatchDocument<ParentObject> patchDoc) => Results.NoContent());
schemas.MapPost("/descriptions", ([Description("Described Parameter")] DescribedDto describedDto) => Results.NoContent());

return endpointRouteBuilder;
}
Expand Down Expand Up @@ -101,4 +102,17 @@ public sealed class ChildObject
public int Id { get; set; }
public required ParentObject Parent { get; set; }
}

[Description("Type Description")]
public sealed class DescribedDto
{
[Description("Property Description on string")]
public string DescribedString { get; set; }

[Description("Property Description on Referenced Object")]
public Tag ReferencedTag { get; set; }

[Description("Property Description on Second Referenced Object")]
public Tag SecondReferencedTag { get; set; }
}
}
23 changes: 23 additions & 0 deletions src/OpenApi/sample/Endpoints/MapXmlEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public static IEndpointRouteBuilder MapXmlEndpoints(this IEndpointRouteBuilder e

group.MapPost("/todo-with-description", (TodoWithDescription todo) => { });

group.MapGet("/list", () => TypedResults.Ok(new TodoList()));

return endpointRouteBuilder;
}

Expand Down Expand Up @@ -111,4 +113,25 @@ public class TodoWithDescription : ITodo
/// <value>Another description of the todo.</value>
public required string Description { get; set; }
}

/// <summary>
/// TodoList to show references.
/// </summary>
public class TodoList
{
/// <summary>
/// A description of the list of Todo Items.
/// </summary>
public List<TodoWithDescription> Items { get; set; } = [];

/// <summary>
/// Last completed Todo.
/// </summary>
public TodoWithDescription LastCompleted { get; set; } = null!;

/// <summary>
/// First completed Todo.
/// </summary>
public TodoWithDescription FirstCompleted { get; set; } = null!;
}
}
11 changes: 11 additions & 0 deletions src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,17 @@ public static void ReadProperty(ref Utf8JsonReader reader, string propertyName,
schema.Metadata ??= new Dictionary<string, object>();
schema.Metadata[OpenApiConstants.RefId] = reader.GetString() ?? string.Empty;
break;
case OpenApiConstants.RefDescriptionAnnotation:
reader.Read();
schema.Metadata ??= new Dictionary<string, object>();
schema.Metadata[OpenApiConstants.RefDescriptionAnnotation] = reader.GetString() ?? string.Empty;
break;
case OpenApiConstants.RefExampleAnnotation:
reader.Read();
schema.Metadata ??= new Dictionary<string, object>();
schema.Metadata[OpenApiConstants.RefExampleAnnotation] = reader.GetString() ?? string.Empty;
break;

default:
reader.Skip();
break;
Expand Down
34 changes: 24 additions & 10 deletions src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,34 @@ internal sealed class OpenApiSchemaService(
{
schema.ApplyNullabilityContextInfo(jsonPropertyInfo);
}
var isInlinedSchema = schema["x-schema-id"] is null;
if (isInlinedSchema && context.PropertyInfo is { AttributeProvider: { } attributeProvider })
if (context.TypeInfo.Type.GetCustomAttributes(inherit: false).OfType<DescriptionAttribute>().LastOrDefault() is DescriptionAttribute typeDescriptionAttribute)
{
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<ValidationAttribute>() is { } validationAttributes)
{
schema.ApplyValidationAttributes(validationAttributes);
}
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<DefaultValueAttribute>().LastOrDefault() is DefaultValueAttribute defaultValueAttribute)
schema[OpenApiSchemaKeywords.DescriptionKeyword] = typeDescriptionAttribute.Description;
}
if (context.PropertyInfo is { AttributeProvider: { } attributeProvider })
{
var isInlinedSchema = schema["x-schema-id"] is null;
if (isInlinedSchema)
{
schema.ApplyDefaultValue(defaultValueAttribute.Value, context.TypeInfo);
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<ValidationAttribute>() is { } validationAttributes)
{
schema.ApplyValidationAttributes(validationAttributes);
}
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<DefaultValueAttribute>().LastOrDefault() is DefaultValueAttribute defaultValueAttribute)
{
schema.ApplyDefaultValue(defaultValueAttribute.Value, context.TypeInfo);
}
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<DescriptionAttribute>().LastOrDefault() is DescriptionAttribute descriptionAttribute)
{
schema[OpenApiSchemaKeywords.DescriptionKeyword] = descriptionAttribute.Description;
}
}
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<DescriptionAttribute>().LastOrDefault() is DescriptionAttribute descriptionAttribute)
else
{
schema[OpenApiSchemaKeywords.DescriptionKeyword] = descriptionAttribute.Description;
if (attributeProvider.GetCustomAttributes(inherit: false).OfType<DescriptionAttribute>().LastOrDefault() is DescriptionAttribute descriptionAttribute)
{
schema[OpenApiConstants.RefDescriptionAnnotation] = descriptionAttribute.Description;
}
}
}

Expand Down
Loading