diff --git a/samples/Aliencube.AzureFunctions.FunctionApp.Models/OrderStatus.cs b/samples/Aliencube.AzureFunctions.FunctionApp.Models/OrderStatus.cs index c860ab3..88bb401 100644 --- a/samples/Aliencube.AzureFunctions.FunctionApp.Models/OrderStatus.cs +++ b/samples/Aliencube.AzureFunctions.FunctionApp.Models/OrderStatus.cs @@ -1,3 +1,5 @@ +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; + using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -12,16 +14,19 @@ public enum OrderStatus /// /// Identifies as "placed". /// + [Display("placed")] Placed = 1, /// /// Identifies as "approved". /// + [Display("approved")] Approved = 2, /// /// Identifies as "delivered". /// + [Display("delivered")] Delivered = 3 } } diff --git a/samples/Aliencube.AzureFunctions.FunctionApp.Models/PetStatus.cs b/samples/Aliencube.AzureFunctions.FunctionApp.Models/PetStatus.cs index d4dd3c8..a8fb7f3 100644 --- a/samples/Aliencube.AzureFunctions.FunctionApp.Models/PetStatus.cs +++ b/samples/Aliencube.AzureFunctions.FunctionApp.Models/PetStatus.cs @@ -1,3 +1,5 @@ +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; + using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -12,16 +14,19 @@ public enum PetStatus /// /// Identifies as "available". /// + [Display("available")] Available = 1, /// /// Identifies as "pending". /// + [Display("pending")] Pending = 2, /// /// Identifies as "sold". /// + [Display("sold")] Sold = 3 } } diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/Aliencube.AzureFunctions.FunctionAppV1IoC.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/Aliencube.AzureFunctions.FunctionAppV1IoC.csproj index ef17f79..c8dc2e4 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/Aliencube.AzureFunctions.FunctionAppV1IoC.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/Aliencube.AzureFunctions.FunctionAppV1IoC.csproj @@ -6,12 +6,12 @@ - + - + @@ -29,10 +29,10 @@ - + diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/PetStoreHttpTrigger.cs b/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/PetStoreHttpTrigger.cs index 4c6a3a8..9138e12 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/PetStoreHttpTrigger.cs +++ b/samples/Aliencube.AzureFunctions.FunctionAppV1IoC/PetStoreHttpTrigger.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -21,6 +22,7 @@ public static class PetStoreHttpTrigger /// /// Gets the instance as an IoC container. /// + [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "")] public static IFunctionFactory Factory = new FunctionFactory(); [FunctionName(nameof(PetStoreHttpTrigger.AddPet))] diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV1Static/Aliencube.AzureFunctions.FunctionAppV1Static.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV1Static/Aliencube.AzureFunctions.FunctionAppV1Static.csproj index e66fb41..17b7ee5 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV1Static/Aliencube.AzureFunctions.FunctionAppV1Static.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV1Static/Aliencube.AzureFunctions.FunctionAppV1Static.csproj @@ -6,12 +6,12 @@ - + - + @@ -29,10 +29,10 @@ - + diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV2IoC/Aliencube.AzureFunctions.FunctionAppV2IoC.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV2IoC/Aliencube.AzureFunctions.FunctionAppV2IoC.csproj index b9dbde8..45431f0 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV2IoC/Aliencube.AzureFunctions.FunctionAppV2IoC.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV2IoC/Aliencube.AzureFunctions.FunctionAppV2IoC.csproj @@ -6,13 +6,13 @@ - + - + @@ -29,10 +29,10 @@ - + \ No newline at end of file diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV2Static/Aliencube.AzureFunctions.FunctionAppV2Static.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV2Static/Aliencube.AzureFunctions.FunctionAppV2Static.csproj index c09f7b3..6971207 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV2Static/Aliencube.AzureFunctions.FunctionAppV2Static.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV2Static/Aliencube.AzureFunctions.FunctionAppV2Static.csproj @@ -6,12 +6,12 @@ - + - + @@ -25,10 +25,10 @@ - + \ No newline at end of file diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV3IoC/Aliencube.AzureFunctions.FunctionAppV3IoC.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV3IoC/Aliencube.AzureFunctions.FunctionAppV3IoC.csproj index a8e5c9c..5c1d038 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV3IoC/Aliencube.AzureFunctions.FunctionAppV3IoC.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV3IoC/Aliencube.AzureFunctions.FunctionAppV3IoC.csproj @@ -6,13 +6,13 @@ - + - + @@ -29,10 +29,10 @@ - + \ No newline at end of file diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV3Static/Aliencube.AzureFunctions.FunctionAppV3Static.csproj b/samples/Aliencube.AzureFunctions.FunctionAppV3Static/Aliencube.AzureFunctions.FunctionAppV3Static.csproj index eb572db..cf78c88 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV3Static/Aliencube.AzureFunctions.FunctionAppV3Static.csproj +++ b/samples/Aliencube.AzureFunctions.FunctionAppV3Static/Aliencube.AzureFunctions.FunctionAppV3Static.csproj @@ -6,12 +6,12 @@ - + - + @@ -25,10 +25,10 @@ - + \ No newline at end of file diff --git a/samples/Aliencube.AzureFunctions.FunctionAppV3Static/PetStoreHttpTrigger.cs b/samples/Aliencube.AzureFunctions.FunctionAppV3Static/PetStoreHttpTrigger.cs index 382799b..720d6f1 100644 --- a/samples/Aliencube.AzureFunctions.FunctionAppV3Static/PetStoreHttpTrigger.cs +++ b/samples/Aliencube.AzureFunctions.FunctionAppV3Static/PetStoreHttpTrigger.cs @@ -45,6 +45,7 @@ public static async Task UpdatePet( [FunctionName(nameof(PetStoreHttpTrigger.FindByStatus))] [OpenApiOperation(operationId: "findPetsByStatus", tags: new[] { "pet" }, Summary = "Finds Pets by status", Description = "Multiple status values can be provided with comma separated strings.", Visibility = OpenApiVisibilityType.Important)] + //[OpenApiParameter(name: "status", In = ParameterLocation.Query, Required = true, Type = typeof(PetStatus), Summary = "Pet status value", Description = "Status values that need to be considered for filter", Visibility = OpenApiVisibilityType.Important)] [OpenApiParameter(name: "status", In = ParameterLocation.Query, Required = true, Type = typeof(List), Summary = "Pet status value", Description = "Status values that need to be considered for filter", Visibility = OpenApiVisibilityType.Important)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(List), Summary = "successful operation", Description = "successful operation")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.BadRequest, Summary = "Invalid status value", Description = "Invalid status value")] diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Attributes/OpenApiParameterAttribute.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Attributes/OpenApiParameterAttribute.cs index 2763a49..c2c59d7 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Attributes/OpenApiParameterAttribute.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Attributes/OpenApiParameterAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; @@ -46,6 +46,17 @@ public OpenApiParameterAttribute(string name) /// public virtual ParameterLocation In { get; set; } = ParameterLocation.Path; + /// + /// Gets or sets the parameter collection delimiter. Default is . + /// + public virtual OpenApiParameterCollectionDelimiterType CollectionDelimiter { get; set; } = OpenApiParameterCollectionDelimiterType.Comma; + + /// + /// Gets or sets the value indicating whether the same query string parameter can be used multiple times or not. + /// This value is only valid when the parameter value is . + /// + public virtual bool Explode { get; set; } + /// /// Gets or sets the value indicating whether the parameter is required or not. Default is false. /// @@ -56,4 +67,4 @@ public OpenApiParameterAttribute(string name) /// public virtual OpenApiVisibilityType Visibility { get; set; } = OpenApiVisibilityType.Undefined; } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Document.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Document.cs index e160c87..130c3a1 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Document.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Document.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; #if NET461 using System.Net.Http; @@ -42,9 +42,9 @@ public Document(IDocumentHelper helper) public IDocument InitialiseDocument() { this._document = new OpenApiDocument() - { - Components = new OpenApiComponents() - }; + { + Components = new OpenApiComponents() + }; return this; } @@ -121,9 +121,9 @@ public IDocument Build(Assembly assembly, NamingStrategy namingStrategy = null) continue; } - operation.Parameters = this._helper.GetOpenApiParameters(method, trigger); - operation.RequestBody = this._helper.GetOpenApiRequestBody(method); - operation.Responses = this._helper.GetOpenApiResponses(method); + operation.Parameters = this._helper.GetOpenApiParameters(method, trigger, namingStrategy); + operation.RequestBody = this._helper.GetOpenApiRequestBody(method, namingStrategy); + operation.Responses = this._helper.GetOpenApiResponses(method, namingStrategy); operations[verb] = operation; item.Operations = operations; @@ -158,4 +158,4 @@ private string Render(OpenApiSpecVersion version, OpenApiFormat format) } } } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/DocumentHelper.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/DocumentHelper.cs index 598d28c..762b5f8 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/DocumentHelper.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/DocumentHelper.cs @@ -119,10 +119,10 @@ public OpenApiOperation GetOpenApiOperation(MethodInfo element, FunctionNameAttr } /// - public List GetOpenApiParameters(MethodInfo element, HttpTriggerAttribute trigger) + public List GetOpenApiParameters(MethodInfo element, HttpTriggerAttribute trigger, NamingStrategy namingStrategy = null) { var parameters = element.GetCustomAttributes(inherit: false) - .Select(p => p.ToOpenApiParameter()) + .Select(p => p.ToOpenApiParameter(namingStrategy)) .ToList(); // This needs to be provided separately. @@ -143,7 +143,7 @@ public OpenApiRequestBody GetOpenApiRequestBody(MethodInfo element, NamingStrate return null; } - var contents = attributes.ToDictionary(p => p.ContentType, p => p.ToOpenApiMediaType()); + var contents = attributes.ToDictionary(p => p.ContentType, p => p.ToOpenApiMediaType(namingStrategy)); if (contents.Any()) { diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiFormatType.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiFormatType.cs index 7aae9cb..54e5c2a 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiFormatType.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiFormatType.cs @@ -1,4 +1,4 @@ -using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; namespace Aliencube.AzureFunctions.Extensions.OpenApi.Enums { diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiParameterCollectionDelimiterType.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiParameterCollectionDelimiterType.cs new file mode 100644 index 0000000..7418313 --- /dev/null +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Enums/OpenApiParameterCollectionDelimiterType.cs @@ -0,0 +1,28 @@ +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; + +namespace Aliencube.AzureFunctions.Extensions.OpenApi.Enums +{ + /// + /// This specifies the parameter collection delimiter. + /// + public enum OpenApiParameterCollectionDelimiterType + { + /// + /// Identifies "comma". + /// + [Display("comma")] + Comma = 0, + + /// + /// Identifies "space". + /// + [Display("space")] + Space = 1, + + /// + /// Identifies "pipe". + /// + [Display("pipe")] + Pipe = 2 + } +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/EnumExtensions.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/EnumExtensions.cs index a1bad37..a1e1d10 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/EnumExtensions.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/EnumExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Reflection; @@ -37,6 +37,11 @@ public static string ToDisplayName(this Enum @enum) public static string ToDataType(this Type type) { var @enum = Type.GetTypeCode(type); + if (!type.IsNullOrDefault() && type.IsEnum) + { + @enum = TypeCode.String; + } + switch (@enum) { case TypeCode.Int16: @@ -95,6 +100,11 @@ public static string ToDataType(this Type type) public static string ToDataFormat(this Type type) { var @enum = Type.GetTypeCode(type); + if (!type.IsNullOrDefault() && type.IsEnum) + { + @enum = TypeCode.String; + } + switch (@enum) { case TypeCode.Int16: @@ -123,6 +133,7 @@ public static string ToDataFormat(this Type type) case TypeCode.Boolean: case TypeCode.String: return null; + case TypeCode.Object: if (type == typeof(Guid)) { @@ -192,4 +203,4 @@ public static OpenApiFormat ToOpenApiFormat(this OpenApiFormatType format) return casted; } } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiParameterAttributeExtensions.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiParameterAttributeExtensions.cs index d41b8fe..8ca65da 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiParameterAttributeExtensions.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiParameterAttributeExtensions.cs @@ -1,4 +1,5 @@ -using System; +using System.Linq; +using System.Reflection; using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; @@ -6,6 +7,10 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + namespace Aliencube.AzureFunctions.Extensions.OpenApi.Extensions { /// @@ -17,24 +22,78 @@ public static class OpenApiParameterAttributeExtensions /// Converts to . /// /// instance. + /// /// instance. - public static OpenApiParameter ToOpenApiParameter(this OpenApiParameterAttribute attribute) + public static OpenApiParameter ToOpenApiParameter(this OpenApiParameterAttribute attribute, NamingStrategy namingStrategy = null) { attribute.ThrowIfNullOrDefault(); + var type = attribute.Type; + var schema = new OpenApiSchema() - { - Type = attribute.Type.ToDataType(), - Format = attribute.Type.ToDataFormat() - }; + { + Type = type.ToDataType(), + Format = type.ToDataFormat(), + }; + + if (type.IsOpenApiArray()) + { + schema.Type = "array"; + schema.Format = null; + schema.Items = (type.GetElementType() ?? type.GetGenericArguments()[0]).ToOpenApiSchema(namingStrategy); + } + + if (type.IsUnflaggedEnumType()) + { + var converterAttribute = type.GetCustomAttribute(); + if (!converterAttribute.IsNullOrDefault() + && typeof(StringEnumConverter).IsAssignableFrom(converterAttribute.ConverterType)) + { + var enums = type.ToOpenApiStringCollection(namingStrategy); + + schema.Type = "string"; + schema.Format = null; + schema.Enum = enums; + schema.Default = enums.First(); + } + else + { + var enums = type.ToOpenApiIntegerCollection(); + + schema.Enum = enums; + schema.Default = enums.First(); + } + } + var parameter = new OpenApiParameter() - { - Name = attribute.Name, - Description = attribute.Description, - Required = attribute.Required, - In = attribute.In, - Schema = schema - }; + { + Name = attribute.Name, + Description = attribute.Description, + Required = attribute.Required, + In = attribute.In, + Schema = schema + }; + + if (type.IsOpenApiArray()) + { + if (attribute.In == ParameterLocation.Path) + { + parameter.Style = ParameterStyle.Simple; + parameter.Explode = false; + } + + if (attribute.In == ParameterLocation.Query) + { + parameter.Style = attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Comma + ? ParameterStyle.Form + : (attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Space + ? ParameterStyle.SpaceDelimited + : ParameterStyle.PipeDelimited); + parameter.Explode = attribute.CollectionDelimiter == OpenApiParameterCollectionDelimiterType.Comma + ? attribute.Explode + : false; + } + } if (!string.IsNullOrWhiteSpace(attribute.Summary)) { @@ -53,4 +112,4 @@ public static OpenApiParameter ToOpenApiParameter(this OpenApiParameterAttribute return parameter; } } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiPayloadAttributeExtensions.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiPayloadAttributeExtensions.cs index b514cc1..4db7dac 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiPayloadAttributeExtensions.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiPayloadAttributeExtensions.cs @@ -1,4 +1,4 @@ -using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; using Microsoft.OpenApi.Models; @@ -22,56 +22,56 @@ public static OpenApiMediaType ToOpenApiMediaType(this T attribute, NamingStr { attribute.ThrowIfNullOrDefault(); - bool isJObject = attribute.BodyType.IsJObjectType(); - bool isDictionary = attribute.BodyType.IsOpenApiDictionary(); - bool isList = attribute.BodyType.IsOpenApiArray(); - bool isGeneric = attribute.BodyType.IsGenericType; - bool isSimpleType = (isDictionary || isList) - ? attribute.BodyType.GetOpenApiSubType().IsSimpleType() - : attribute.BodyType.IsSimpleType(); + var isJObject = attribute.BodyType.IsJObjectType(); + var isDictionary = attribute.BodyType.IsOpenApiDictionary(); + var isList = attribute.BodyType.IsOpenApiArray(); + var isGeneric = attribute.BodyType.IsGenericType; + var isSimpleType = (isDictionary || isList) + ? attribute.BodyType.GetOpenApiSubType().IsSimpleType() + : attribute.BodyType.IsSimpleType(); var reference = new OpenApiReference() - { - Type = ReferenceType.Schema, - Id = attribute.BodyType.GetOpenApiReferenceId(isDictionary, isList) - }; + { + Type = ReferenceType.Schema, + Id = attribute.BodyType.GetOpenApiReferenceId(isDictionary, isList) + }; var schema = new OpenApiSchema() { Reference = reference }; if (isJObject) { schema = new OpenApiSchema() - { - Type = "object" - }; + { + Type = "object" + }; } else if (isDictionary) { schema = new OpenApiSchema() - { - Type = "object", - AdditionalProperties = isSimpleType - ? attribute.BodyType.GetOpenApiSubType().ToOpenApiSchema(namingStrategy) - : schema - }; + { + Type = "object", + AdditionalProperties = isSimpleType + ? attribute.BodyType.GetOpenApiSubType().ToOpenApiSchema(namingStrategy) + : schema + }; } else if (isList) { schema = new OpenApiSchema() - { - Type = "array", - Items = isSimpleType - ? attribute.BodyType.GetOpenApiSubType().ToOpenApiSchema(namingStrategy) - : schema - }; + { + Type = "array", + Items = isSimpleType + ? attribute.BodyType.GetOpenApiSubType().ToOpenApiSchema(namingStrategy) + : schema + }; } else if (isGeneric) { reference = new OpenApiReference() - { - Type = ReferenceType.Schema, - Id = attribute.BodyType.GetOpenApiRootReferenceId() - }; + { + Type = ReferenceType.Schema, + Id = attribute.BodyType.GetOpenApiRootReferenceId() + }; schema = new OpenApiSchema() { Reference = reference }; } @@ -85,4 +85,4 @@ public static OpenApiMediaType ToOpenApiMediaType(this T attribute, NamingStr return mediaType; } } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiSchemaExtensions.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiSchemaExtensions.cs index 83eb51e..d451b6c 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/OpenApiSchemaExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -98,13 +98,19 @@ public static Dictionary ToOpenApiSchemas(this Type type, if (!converterAttribute.IsNullOrDefault() && typeof(StringEnumConverter).IsAssignableFrom(converterAttribute.ConverterType)) { + var enums = type.ToOpenApiStringCollection(namingStrategy); + schema.Type = "string"; schema.Format = null; - schema.Enum = type.ToOpenApiStringCollection(namingStrategy); + schema.Enum = enums; + schema.Default = enums.First(); } else { - schema.Enum = type.ToOpenApiIntegerCollection(); + var enums = type.ToOpenApiIntegerCollection(); + + schema.Enum = enums; + schema.Default = enums.First(); } } diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/TypeExtensions.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/TypeExtensions.cs index c60a866..1842e6a 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/TypeExtensions.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/Extensions/TypeExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -408,4 +408,4 @@ private static bool IsDictionaryType(this Type type) return false; } } -} \ No newline at end of file +} diff --git a/src/Aliencube.AzureFunctions.Extensions.OpenApi/IDocumentHelper.cs b/src/Aliencube.AzureFunctions.Extensions.OpenApi/IDocumentHelper.cs index 7735970..c3788f7 100644 --- a/src/Aliencube.AzureFunctions.Extensions.OpenApi/IDocumentHelper.cs +++ b/src/Aliencube.AzureFunctions.Extensions.OpenApi/IDocumentHelper.cs @@ -72,8 +72,9 @@ public interface IDocumentHelper /// /// instance. /// instance. + /// instance to create the JSON schema from .NET Types. /// List of instance. - List GetOpenApiParameters(MethodInfo element, HttpTriggerAttribute trigger); + List GetOpenApiParameters(MethodInfo element, HttpTriggerAttribute trigger, NamingStrategy namingStrategy = null); /// /// Gets the instance. diff --git a/templates/OpenApiEndpints/IOpenApiHttpTriggerContext.cs b/templates/OpenApiEndpints/IOpenApiHttpTriggerContext.cs index 856a0b3..030703e 100644 --- a/templates/OpenApiEndpints/IOpenApiHttpTriggerContext.cs +++ b/templates/OpenApiEndpints/IOpenApiHttpTriggerContext.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using Aliencube.AzureFunctions.Extensions.OpenApi.Abstractions; using Aliencube.AzureFunctions.Extensions.OpenApi.Configurations; @@ -7,6 +7,8 @@ using Microsoft.OpenApi; using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Serialization; + namespace Aliencube.AzureFunctions.Extensions.OpenApi { /// @@ -34,6 +36,11 @@ public interface IOpenApiHttpTriggerContext /// ISwaggerUI SwaggerUI { get; } + /// + /// Gets the instance. + /// + NamingStrategy NamingStrategy { get; } + /// /// Gets the executing assembly. /// diff --git a/templates/OpenApiEndpints/OpenApiHttpTrigger.cs b/templates/OpenApiEndpints/OpenApiHttpTrigger.cs index 9ac726d..5d859e7 100644 --- a/templates/OpenApiEndpints/OpenApiHttpTrigger.cs +++ b/templates/OpenApiEndpints/OpenApiHttpTrigger.cs @@ -1,4 +1,4 @@ -#if !NET461 +#if !NET461 using System.Net; using System.Threading.Tasks; @@ -45,7 +45,7 @@ public static async Task RenderSwaggerDocument( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(extension)) .ConfigureAwait(false); @@ -81,7 +81,7 @@ public static async Task RenderOpenApiDocument( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(version), context.GetOpenApiFormat(extension)) .ConfigureAwait(false); diff --git a/templates/OpenApiEndpints/OpenApiHttpTriggerContext.cs b/templates/OpenApiEndpints/OpenApiHttpTriggerContext.cs index 718c461..cc0eb61 100644 --- a/templates/OpenApiEndpints/OpenApiHttpTriggerContext.cs +++ b/templates/OpenApiEndpints/OpenApiHttpTriggerContext.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Reflection; -using Aliencube.AzureFunctions.Extensions.OpenApi; using Aliencube.AzureFunctions.Extensions.OpenApi.Abstractions; using Aliencube.AzureFunctions.Extensions.OpenApi.Configurations; using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; @@ -11,6 +10,8 @@ using Microsoft.OpenApi; using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Serialization; + namespace Aliencube.AzureFunctions.Extensions.OpenApi { /// @@ -47,6 +48,9 @@ public OpenApiHttpTriggerContext() /// public virtual ISwaggerUI SwaggerUI { get; } + /// + public virtual NamingStrategy NamingStrategy { get; } = new CamelCaseNamingStrategy(); + /// public virtual Assembly GetExecutingAssembly() { diff --git a/templates/OpenApiEndpints/OpenApiHttpTriggerV1.cs b/templates/OpenApiEndpints/OpenApiHttpTriggerV1.cs index 272853f..0a1f004 100644 --- a/templates/OpenApiEndpints/OpenApiHttpTriggerV1.cs +++ b/templates/OpenApiEndpints/OpenApiHttpTriggerV1.cs @@ -1,4 +1,4 @@ -#if NET461 +#if NET461 using System.Net; using System.Net.Http; using System.Text; @@ -43,7 +43,7 @@ public static async Task RenderSwaggerDocumentInJson( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(JSON)) .ConfigureAwait(false); @@ -71,7 +71,7 @@ public static async Task RenderSwaggerDocumentInYml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); @@ -99,7 +99,7 @@ public static async Task RenderSwaggerDocumentInYaml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); @@ -127,7 +127,7 @@ public static async Task RenderOpenApiDocumentV2InJson( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(JSON)) .ConfigureAwait(false); @@ -155,7 +155,7 @@ public static async Task RenderOpenApiDocumentV2InYml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); @@ -183,7 +183,7 @@ public static async Task RenderOpenApiDocumentV2InYaml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V2), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); @@ -211,7 +211,7 @@ public static async Task RenderOpenApiDocumentV3InJson( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V3), context.GetOpenApiFormat(JSON)) .ConfigureAwait(false); @@ -239,7 +239,7 @@ public static async Task RenderOpenApiDocumentV3InYml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V3), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); @@ -267,7 +267,7 @@ public static async Task RenderOpenApiDocumentV3InYaml( .InitialiseDocument() .AddMetadata(context.OpenApiInfo) .AddServer(req, context.HttpSettings.RoutePrefix) - .Build(context.GetExecutingAssembly()) + .Build(context.GetExecutingAssembly(), context.NamingStrategy) .RenderAsync(context.GetOpenApiSpecVersion(V3), context.GetOpenApiFormat(YAML)) .ConfigureAwait(false); diff --git a/test/Aliencube.AzureFunctions.Extensions.DependencyInjection.Tests.Fakes/FakeFunctionWithTraceWriter.cs b/test/Aliencube.AzureFunctions.Extensions.DependencyInjection.Tests.Fakes/FakeFunctionWithTraceWriter.cs index ba21ab7..d5734f5 100644 --- a/test/Aliencube.AzureFunctions.Extensions.DependencyInjection.Tests.Fakes/FakeFunctionWithTraceWriter.cs +++ b/test/Aliencube.AzureFunctions.Extensions.DependencyInjection.Tests.Fakes/FakeFunctionWithTraceWriter.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Aliencube.AzureFunctions.Extensions.DependencyInjection.Abstractions; diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes/FakeEnum.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes/FakeEnum.cs index 07ec118..441f1c5 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes/FakeEnum.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes/FakeEnum.cs @@ -1,10 +1,14 @@ -using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; + +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes { /// /// This specifies fake enum values. /// + [JsonConverter(typeof(StringEnumConverter))] public enum FakeEnum { Value1, diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.csproj b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.csproj index 77803dd..320a46b 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.csproj +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Aliencube.AzureFunctions.Extensions.OpenApi.Tests.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.1;netcoreapp3.1 @@ -18,7 +18,7 @@ - + diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiParameterAttributeTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiParameterAttributeTests.cs index cd3589d..5664c9c 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiParameterAttributeTests.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiParameterAttributeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; @@ -32,6 +32,8 @@ public void Given_Value_Property_Should_Return_Value() attribute.Description.Should().BeNullOrWhiteSpace(); attribute.Type.Should().Be(); attribute.In.Should().Be(ParameterLocation.Path); + attribute.CollectionDelimiter.Should().Be(OpenApiParameterCollectionDelimiterType.Comma); + attribute.Explode.Should().Be(false); attribute.Required.Should().Be(false); attribute.Visibility.Should().Be(OpenApiVisibilityType.Undefined); } diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiRequestBodyAttributeTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiRequestBodyAttributeTests.cs index 8cd0645..70f5aa2 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiRequestBodyAttributeTests.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Attributes/OpenApiRequestBodyAttributeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; @@ -31,6 +31,7 @@ public void Given_Value_Property_Should_Return_Value() attribute.ContentType.Should().BeEquivalentTo(contentType); attribute.BodyType.Should().Be(bodyType); attribute.Description.Should().BeNullOrWhiteSpace(); + attribute.Required.Should().Be(false); } } } diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiFormatTypeTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiFormatTypeTests.cs index 899d6e6..2abbaeb 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiFormatTypeTests.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiFormatTypeTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Reflection; using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiParameterCollectionDelimiterTypeTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiParameterCollectionDelimiterTypeTests.cs new file mode 100644 index 0000000..a0e61e8 --- /dev/null +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Enums/OpenApiParameterCollectionDelimiterTypeTests.cs @@ -0,0 +1,47 @@ +using System.Linq; +using System.Reflection; + +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; +using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; + +using FluentAssertions; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Enums +{ + [TestClass] + public class OpenApiParameterCollectionDelimiterTypeTests + { + [DataTestMethod] + [DataRow("Comma")] + [DataRow("Space")] + [DataRow("Pipe")] + public void Given_Enum_Should_Have_Member(string memberName) + { + var members = typeof(OpenApiParameterCollectionDelimiterType).GetMembers().Select(p => p.Name); + + members.Should().Contain(memberName); + } + + [DataTestMethod] + [DataRow("Comma", "comma")] + [DataRow("Space", "space")] + [DataRow("Pipe", "pipe")] + public void Given_Enum_Should_Have_Decorator(string memberName, string displayName) + { + var member = this.GetMemberInfo(memberName); + var attribute = member.GetCustomAttribute(inherit: false); + + attribute.Should().NotBeNull(); + attribute.Name.Should().Be(displayName); + } + + private MemberInfo GetMemberInfo(string name) + { + var member = typeof(OpenApiParameterCollectionDelimiterType).GetMember(name).First(); + + return member; + } + } +} diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/EnumExtensionsTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/EnumExtensionsTests.cs index 0e7166d..2d78a88 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/EnumExtensionsTests.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/EnumExtensionsTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; using Aliencube.AzureFunctions.Extensions.OpenApi.Extensions; diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiParameterAttributeExtensionsTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiParameterAttributeExtensionsTests.cs new file mode 100644 index 0000000..5183cfe --- /dev/null +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiParameterAttributeExtensionsTests.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; +using Aliencube.AzureFunctions.Extensions.OpenApi.Enums; +using Aliencube.AzureFunctions.Extensions.OpenApi.Extensions; +using Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Fakes; + +using FluentAssertions; + +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Newtonsoft.Json.Serialization; + +namespace Aliencube.AzureFunctions.Extensions.OpenApi.Tests.Extensions +{ + [TestClass] + public class OpenApiParameterAttributeExtensionsTests + { + [TestMethod] + public void Given_Null_When_ToOpenApiParameter_Invoked_Then_It_Should_Throw_Exception() + { + Action action = () => OpenApiParameterAttributeExtensions.ToOpenApiParameter(null); + + action.Should().Throw(); + } + + [TestMethod] + public void Given_Value_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(string), + Description = "hello world", + Required = true, + In = ParameterLocation.Path + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Name.Should().Be(attribute.Name); + result.Description.Should().Be(attribute.Description); + result.Required.Should().Be(attribute.Required); + result.In.Should().Be(attribute.In); + } + + [TestMethod] + public void Given_Value_With_String_Type_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(string), + Description = "hello world", + Required = true, + In = ParameterLocation.Path + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Schema.Type.Should().Be("string"); + result.Schema.Format.Should().BeNull(); + } + + [TestMethod] + public void Given_Value_With_Int_Type_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(int), + Description = "hello world", + Required = true, + In = ParameterLocation.Path + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Schema.Type.Should().Be("integer"); + result.Schema.Format.Should().Be("int32"); + } + + [TestMethod] + public void Given_Value_With_Long_Type_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(long), + Description = "hello world", + Required = true, + In = ParameterLocation.Path + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Schema.Type.Should().Be("integer"); + result.Schema.Format.Should().Be("int64"); + } + + [TestMethod] + public void Given_Value_With_Enum_Type_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var strategy = new CamelCaseNamingStrategy(); + var names = typeof(FakeEnum).ToOpenApiStringCollection(strategy).Select(p => (p as OpenApiString).Value).ToList(); + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(FakeEnum), + Description = "hello world", + Required = true, + In = ParameterLocation.Query + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute, strategy); + + result.Style.Should().BeNull(); + result.Explode.Should().Be(attribute.Explode); + + result.Schema.Type.Should().Be("string"); + result.Schema.Format.Should().BeNull(); + + result.Schema.Enum.Should().HaveCount(names.Count); + (result.Schema.Default as OpenApiString).Value.Should().Be(names.First()); + } + + [TestMethod] + public void Given_Value_With_List_Enum_Type_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var strategy = new CamelCaseNamingStrategy(); + var names = typeof(FakeEnum).ToOpenApiStringCollection(strategy).Select(p => (p as OpenApiString).Value).ToList(); + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(List), + Description = "hello world", + Required = true, + In = ParameterLocation.Query + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute, strategy); + + result.Style.Should().Be(ParameterStyle.Form); + result.Explode.Should().Be(attribute.Explode); + + result.Schema.Type.Should().Be("array"); + result.Schema.Format.Should().BeNull(); + result.Schema.Items.Type.Should().Be("string"); + result.Schema.Items.Enum.Should().HaveCount(names.Count); + (result.Schema.Items.Default as OpenApiString).Value.Should().Be(names.First()); + } + + [TestMethod] + public void Given_Value_With_Summary_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(long), + Summary = "lorem ipsum", + Description = "hello world", + Required = true, + In = ParameterLocation.Path + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Extensions.Keys.Should().Contain("x-ms-summary"); + result.Extensions["x-ms-summary"].Should().BeOfType(); + (result.Extensions["x-ms-summary"] as OpenApiString).Value.Should().Be(attribute.Summary); + } + + [TestMethod] + public void Given_Value_With_Visibility_When_ToOpenApiParameter_Invoked_Then_It_Should_Return_Result() + { + var attribute = new OpenApiParameterAttribute("hello") + { + Type = typeof(long), + Summary = "lorem ipsum", + Description = "hello world", + Required = true, + In = ParameterLocation.Path, + Visibility = OpenApiVisibilityType.Important + }; + + var result = OpenApiParameterAttributeExtensions.ToOpenApiParameter(attribute); + + result.Extensions.Keys.Should().Contain("x-ms-visibility"); + result.Extensions["x-ms-visibility"].Should().BeOfType(); + (result.Extensions["x-ms-visibility"] as OpenApiString).Value.Should().Be(attribute.Visibility.ToDisplayName()); + } + } +} diff --git a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiSchemaExtensionsTests.cs b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiSchemaExtensionsTests.cs index 2566470..a1cd177 100644 --- a/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiSchemaExtensionsTests.cs +++ b/test/Aliencube.AzureFunctions.Extensions.OpenApi.Tests/Extensions/OpenApiSchemaExtensionsTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Aliencube.AzureFunctions.Extensions.OpenApi.Attributes; @@ -200,32 +200,34 @@ public void Given_Interface_With_Inheritance_Should_Contain_All_Properties() } [TestMethod] - public void Given_FakeModel_It_Should_Return_Result() + public void Given_FakeModel_When_ToOpenApiSchemas_Invoked_Then_It_Should_Return_Result() { var type = typeof(FakeModel); + var subType = typeof(FakeSubModel); + var enumType = typeof(FakeEnum); + var strategy = new CamelCaseNamingStrategy(); var schemas = OpenApiSchemaExtensions.ToOpenApiSchemas(type, strategy); + schemas.Count.Should().Be(3); - var fmSchema = schemas[type.Name]; - var fsmType = typeof(FakeSubModel); - var fsmSchema = schemas[fsmType.Name]; - var feType = typeof(FakeEnum); - var feSchema = schemas[feType.Name]; - fmSchema.Type.Should().Be("object"); - fmSchema.Properties["fakeProperty"].Type.Should().BeEquivalentTo("string"); - fmSchema.Properties["nullableInt"].Type.Should().BeEquivalentTo("integer"); - fmSchema.Properties["nullableInt"].Nullable.Should().BeTrue(); - fmSchema.Properties["subProperty"].Reference.Id.Should().BeEquivalentTo(fsmType.Name); - fmSchema.Properties["enumProperty"].Reference.Id.Should().BeEquivalentTo(feType.Name); - fsmSchema.Type.Should().Be("object"); - fsmSchema.Properties["fakeSubModelProperty"].Type.Should().BeEquivalentTo("integer"); + var schema = schemas[type.Name]; + var subSchema = schemas[subType.Name]; + var enumSchema = schemas[enumType.Name]; - feSchema.Type.Should().Be("integer"); - feSchema.Enum.Count.Should().Be(2); + schema.Type.Should().Be("object"); + schema.Properties["fakeProperty"].Type.Should().BeEquivalentTo("string"); + schema.Properties["nullableInt"].Type.Should().BeEquivalentTo("integer"); + schema.Properties["nullableInt"].Nullable.Should().BeTrue(); + schema.Properties["subProperty"].Reference.Id.Should().BeEquivalentTo(subType.Name); + schema.Properties["enumProperty"].Reference.Id.Should().BeEquivalentTo(enumType.Name); + subSchema.Type.Should().Be("object"); + subSchema.Properties["fakeSubModelProperty"].Type.Should().BeEquivalentTo("integer"); + enumSchema.Type.Should().Be("string"); + enumSchema.Enum.Count.Should().Be(2); } [TestMethod] @@ -269,4 +271,4 @@ public void Given_FakeModelWithCircularRef_It_Should_Return_Result() } } -} \ No newline at end of file +}