Skip to content

Commit

Permalink
Extend built-in supported types
Browse files Browse the repository at this point in the history
- Ensure `DateOnly` and `TimeOnly` with for Newtonsoft.Json.
- Add System.Text.Json support for `TimeSpan` and `Version`.
- Add Int128 and UInt128 support.
- Handle `AnnotationsDataType.Upload`.
- Create `AnnotationsDataType` mapping dictionary only once.
Resolves domaindrivendev#2611.
  • Loading branch information
martincostello committed Apr 23, 2024
1 parent c936acb commit f881c24
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ public DataContract GetDataContractForType(Type type)

if (jsonContract is JsonPrimitiveContract && !jsonContract.UnderlyingType.IsEnum)
{
var primitiveTypeAndFormat = PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var format)
? format
: Tuple.Create(DataType.String, (string)null);
if (!PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var primitiveTypeAndFormat))
{
primitiveTypeAndFormat = Tuple.Create(DataType.String, (string)null);
}

return DataContract.ForPrimitive(
underlyingType: jsonContract.UnderlyingType,
Expand Down Expand Up @@ -99,6 +100,16 @@ public DataContract GetDataContractForType(Type type)

if (jsonContract is JsonObjectContract jsonObjectContract)
{
// This handles DateOnly and TimeOnly
if (PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var primitiveTypeAndFormat))
{
return DataContract.ForPrimitive(
underlyingType: jsonContract.UnderlyingType,
dataType: primitiveTypeAndFormat.Item1,
dataFormat: primitiveTypeAndFormat.Item2,
jsonConverter: JsonConverterFunc);
}

string typeNameProperty = null;
string typeNameValue = null;

Expand Down Expand Up @@ -210,7 +221,11 @@ private IEnumerable<DataProperty> GetDataPropertiesFor(JsonObjectContract jsonOb
[ typeof(TimeSpan) ] = Tuple.Create(DataType.String, "date-span"),
#if NET6_0_OR_GREATER
[ typeof(DateOnly) ] = Tuple.Create(DataType.String, "date"),
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time")
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time"),
#endif
#if NET7_0_OR_GREATER
[ typeof(Int128) ] = Tuple.Create(DataType.Integer, "int128"),
[ typeof(UInt128) ] = Tuple.Create(DataType.Integer, "int128"),
#endif
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,17 @@ private IEnumerable<DataProperty> GetDataPropertiesFor(Type objectType, out Type
[ typeof(char) ] = Tuple.Create(DataType.String, (string)null),
[ typeof(DateTime) ] = Tuple.Create(DataType.String, "date-time"),
[ typeof(DateTimeOffset) ] = Tuple.Create(DataType.String, "date-time"),
[ typeof(TimeSpan) ] = Tuple.Create(DataType.String, "date-span"),
[ typeof(Guid) ] = Tuple.Create(DataType.String, "uuid"),
[ typeof(Uri) ] = Tuple.Create(DataType.String, "uri"),
[ typeof(Version) ] = Tuple.Create(DataType.String, (string)null),
#if NET6_0_OR_GREATER
[ typeof(DateOnly) ] = Tuple.Create(DataType.String, "date"),
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time")
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time"),
#endif
#if NET7_0_OR_GREATER
[ typeof(Int128) ] = Tuple.Create(DataType.Integer, "int128"),
[ typeof(UInt128) ] = Tuple.Create(DataType.Integer, "int128"),
#endif
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ namespace Swashbuckle.AspNetCore.SwaggerGen
{
public static class OpenApiSchemaExtensions
{
private static readonly Dictionary<AnnotationsDataType, string> DataFormatMappings = new()
{
[AnnotationsDataType.DateTime] = "date-time",
[AnnotationsDataType.Date] = "date",
[AnnotationsDataType.Time] = "time",
[AnnotationsDataType.Duration] = "duration",
[AnnotationsDataType.PhoneNumber] = "tel",
[AnnotationsDataType.Currency] = "currency",
[AnnotationsDataType.Text] = "string",
[AnnotationsDataType.Html] = "html",
[AnnotationsDataType.MultilineText] = "multiline",
[AnnotationsDataType.EmailAddress] = "email",
[AnnotationsDataType.Password] = "password",
[AnnotationsDataType.Url] = "uri",
[AnnotationsDataType.ImageUrl] = "uri",
[AnnotationsDataType.CreditCard] = "credit-card",
[AnnotationsDataType.PostalCode] = "postal-code",
[AnnotationsDataType.Upload] = "binary",
};

public static void ApplyValidationAttributes(this OpenApiSchema schema, IEnumerable<object> customAttributes)
{
foreach (var attribute in customAttributes)
Expand Down Expand Up @@ -88,26 +108,7 @@ public static string ResolveType(this OpenApiSchema schema, SchemaRepository sch

private static void ApplyDataTypeAttribute(OpenApiSchema schema, DataTypeAttribute dataTypeAttribute)
{
var formats = new Dictionary<AnnotationsDataType, string>
{
{ AnnotationsDataType.DateTime, "date-time" },
{ AnnotationsDataType.Date, "date" },
{ AnnotationsDataType.Time, "time" },
{ AnnotationsDataType.Duration, "duration" },
{ AnnotationsDataType.PhoneNumber, "tel" },
{ AnnotationsDataType.Currency, "currency" },
{ AnnotationsDataType.Text, "string" },
{ AnnotationsDataType.Html, "html" },
{ AnnotationsDataType.MultilineText, "multiline" },
{ AnnotationsDataType.EmailAddress, "email" },
{ AnnotationsDataType.Password, "password" },
{ AnnotationsDataType.Url, "uri" },
{ AnnotationsDataType.ImageUrl, "uri" },
{ AnnotationsDataType.CreditCard, "credit-card" },
{ AnnotationsDataType.PostalCode, "postal-code" }
};

if (formats.TryGetValue(dataTypeAttribute.DataType, out string format))
if (DataFormatMappings.TryGetValue(dataTypeAttribute.DataType, out string format))
{
schema.Format = format;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void GenerateSchema_GeneratesFileSchema_IfFormFileOrFileResultType(Type t
}

[Theory]
[InlineData(typeof(bool), "boolean", null)]
[InlineData(typeof(byte), "integer", "int32")]
[InlineData(typeof(sbyte), "integer", "int32")]
[InlineData(typeof(short), "integer", "int32")]
Expand All @@ -48,12 +49,24 @@ public void GenerateSchema_GeneratesFileSchema_IfFormFileOrFileResultType(Type t
[InlineData(typeof(byte[]), "string", "byte")]
[InlineData(typeof(DateTime), "string", "date-time")]
[InlineData(typeof(DateTimeOffset), "string", "date-time")]
[InlineData(typeof(Guid), "string", "uuid")]
[InlineData(typeof(TimeSpan), "string", "date-span")]
[InlineData(typeof(Guid), "string", "uuid")]
[InlineData(typeof(Uri), "string", "uri")]
[InlineData(typeof(Version), "string", null)]
[InlineData(typeof(DateOnly), "string", "date")]
[InlineData(typeof(TimeOnly), "string", "time")]
[InlineData(typeof(bool?), "boolean", null)]
[InlineData(typeof(int?), "integer", "int32")]
[InlineData(typeof(DateTime?), "string", "date-time")]
[InlineData(typeof(Guid?), "string", "uuid")]
[InlineData(typeof(DateOnly?), "string", "date")]
[InlineData(typeof(TimeOnly?), "string", "time")]
#if NET7_0_OR_GREATER
[InlineData(typeof(Int128), "integer", "int128")]
[InlineData(typeof(Int128?), "integer", "int128")]
[InlineData(typeof(UInt128), "integer", "int128")]
[InlineData(typeof(UInt128?), "integer", "int128")]
#endif
public void GenerateSchema_GeneratesPrimitiveSchema_IfPrimitiveOrNullablePrimitiveType(
Type type,
string expectedSchemaType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ public void GenerateSchema_GeneratesFileSchema_IfFormFileOrFileResultType(Type t
[InlineData(typeof(byte[]), "string", "byte")]
[InlineData(typeof(DateTime), "string", "date-time")]
[InlineData(typeof(DateTimeOffset), "string", "date-time")]
[InlineData(typeof(TimeSpan), "string", "date-span")]
[InlineData(typeof(Guid), "string", "uuid")]
[InlineData(typeof(Uri), "string", "uri")]
[InlineData(typeof(Version), "string", null)]
[InlineData(typeof(DateOnly), "string", "date")]
[InlineData(typeof(TimeOnly), "string", "time")]
[InlineData(typeof(bool?), "boolean", null)]
Expand All @@ -61,6 +63,12 @@ public void GenerateSchema_GeneratesFileSchema_IfFormFileOrFileResultType(Type t
[InlineData(typeof(Guid?), "string", "uuid")]
[InlineData(typeof(DateOnly?), "string", "date")]
[InlineData(typeof(TimeOnly?), "string", "time")]
#if NET7_0_OR_GREATER
[InlineData(typeof(Int128), "integer", "int128")]
[InlineData(typeof(Int128?), "integer", "int128")]
[InlineData(typeof(UInt128), "integer", "int128")]
[InlineData(typeof(UInt128?), "integer", "int128")]
#endif
public void GenerateSchema_GeneratesPrimitiveSchema_IfPrimitiveOrNullablePrimitiveType(
Type type,
string expectedSchemaType,
Expand Down

0 comments on commit f881c24

Please sign in to comment.