Skip to content

Commit

Permalink
Extend built-in supported types (#2804)
Browse files Browse the repository at this point in the history
  • Loading branch information
martincostello committed May 6, 2024
1 parent eabfafa commit 4d5625f
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 33 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 All @@ -48,7 +49,7 @@ public DataContract GetDataContractForType(Type type)
{
var enumValues = jsonContract.UnderlyingType.GetEnumValues();

//Test to determine if the serializer will treat as string
// Test to determine if the serializer will treat as string
var serializeAsString = (enumValues.Length > 0)
&& JsonConverterFunc(enumValues.GetValue(0)).StartsWith("\"");

Expand Down Expand Up @@ -83,7 +84,7 @@ public DataContract GetDataContractForType(Type type)
// This is a special case where we know the possible key values
var enumValuesAsJson = keyType.GetEnumValues()
.Cast<object>()
.Select(value => JsonConverterFunc(value));
.Select(JsonConverterFunc);

keys = enumValuesAsJson.Any(json => json.StartsWith("\""))
? enumValuesAsJson.Select(json => json.Replace("\"", string.Empty))
Expand All @@ -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 @@ -186,7 +197,7 @@ private IEnumerable<DataProperty> GetDataPropertiesFor(JsonObjectContract jsonOb
return dataProperties;
}

private static readonly Dictionary<Type, Tuple<DataType, string>> PrimitiveTypesAndFormats = new Dictionary<Type, Tuple<DataType, string>>
private static readonly Dictionary<Type, Tuple<DataType, string>> PrimitiveTypesAndFormats = new()
{
[ typeof(bool) ] = Tuple.Create(DataType.Boolean, (string)null),
[ typeof(byte) ] = Tuple.Create(DataType.Integer, "int32"),
Expand All @@ -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 @@ -27,12 +27,12 @@ public DataContract GetDataContractForType(Type type)
jsonConverter: JsonConverterFunc);
}

if (PrimitiveTypesAndFormats.TryGetValue(type, out var primitiveTypeAndFormat1))
if (PrimitiveTypesAndFormats.TryGetValue(type, out var primitiveTypeAndFormat))
{
return DataContract.ForPrimitive(
underlyingType: type,
dataType: primitiveTypeAndFormat1.Item1,
dataFormat: primitiveTypeAndFormat1.Item2,
dataType: primitiveTypeAndFormat.Item1,
dataFormat: primitiveTypeAndFormat.Item2,
jsonConverter: JsonConverterFunc);
}

Expand All @@ -44,7 +44,7 @@ public DataContract GetDataContractForType(Type type)
var serializeAsString = (enumValues.Length > 0)
&& JsonConverterFunc(enumValues.GetValue(0)).StartsWith("\"");

var primitiveTypeAndFormat = serializeAsString
primitiveTypeAndFormat = serializeAsString
? PrimitiveTypesAndFormats[typeof(string)]
: PrimitiveTypesAndFormats[type.GetEnumUnderlyingType()];

Expand Down Expand Up @@ -254,11 +254,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 @@ -33,6 +33,7 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
}

[Theory]
[InlineData(typeof(bool), "boolean", null)]
[InlineData(typeof(byte), "integer", "int32")]
[InlineData(typeof(sbyte), "integer", "int32")]
[InlineData(typeof(short), "integer", "int32")]
Expand All @@ -49,12 +50,24 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
[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 @@ -53,8 +53,10 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
[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 @@ -63,6 +65,12 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
[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

2 comments on commit 4d5625f

@vierlijner
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add #if NET6_0_OR_GREATER .... #endif around DateOnly en TimeOnly in the test files (*Tests.cs)

@martincostello
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review the PR, not the commits. I won’t be reading further comments in the commits as they aren’t easily consumable in-situ in the PR.

Please sign in to comment.