Skip to content

Commit

Permalink
always prefer modelMetaData.Type over parameter.Type to support Enums.
Browse files Browse the repository at this point in the history
…Fixes #7
  • Loading branch information
Havunen committed Feb 24, 2024
1 parent a542527 commit 1b89744
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,15 @@ private OpenApiParameter GenerateParameter(

var isRequired = apiParameter.IsRequiredParameter();

var schema = apiParameter.ModelMetadata != null
? GenerateSchema(
apiParameter.Type,
schemaRepository,
apiParameter.PropertyInfo(),
apiParameter.ParameterInfo(),
apiParameter.RouteInfo)
: new OpenApiSchema { Type = "string" };
var type = apiParameter.ModelMetadata?.ModelType ?? apiParameter.Type;

var schema = type != null ? GenerateSchema(
type,
schemaRepository,
apiParameter.PropertyInfo(),
apiParameter.ParameterInfo(),
apiParameter.RouteInfo
) : new OpenApiSchema() {Type = "string"};

var parameter = new OpenApiParameter
{
Expand Down Expand Up @@ -513,11 +514,13 @@ private OpenApiRequestBody GenerateRequestBodyFromBodyParameter(

var isRequired = bodyParameter.IsRequiredParameter();

var schema = GenerateSchema(
bodyParameter.Type,
var type = bodyParameter.ModelMetadata?.ModelType ?? bodyParameter.Type;
var schema = type != null ? GenerateSchema(
type,
schemaRepository,
bodyParameter.PropertyInfo(),
bodyParameter.ParameterInfo());
bodyParameter.ParameterInfo()
) : new OpenApiSchema() { Type = "string" };

return new OpenApiRequestBody
{
Expand Down Expand Up @@ -591,13 +594,13 @@ private OpenApiSchema GenerateSchemaFromFormParameters(
? formParameter.Name.ToCamelCase()
: formParameter.Name;

var schema = formParameter.ModelMetadata != null
? GenerateSchema(
formParameter.Type,
schemaRepository,
formParameter.PropertyInfo(),
formParameter.ParameterInfo())
: new OpenApiSchema { Type = "string" };
var type = formParameter.ModelMetadata?.ModelType ?? formParameter.Type;
var schema = type != null ? GenerateSchema(
type,
schemaRepository,
formParameter.PropertyInfo(),
formParameter.ParameterInfo()
) : new OpenApiSchema() { Type = "string" };

properties.Add(name, schema);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using DotSwashbuckle.AspNetCore.TestSupport;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
Expand All @@ -19,6 +20,11 @@ public void ActionWithNoParameters()
public void ActionWithParameter(string param)
{ }

public IntEnum ActionWithEnumParameter(IntEnum param)
{
return param;
}

public void ActionWithMultipleParameters(string param1, int param2)
{ }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,109 @@ public void GetSwagger_SetsOperationIdToNull_IfActionHasNoEndpointMetadata()
Assert.Null(document.Paths["/resource"].Operations[OperationType.Post].OperationId);
}

[Fact]
public void GetSwagger_SetsEnumRef_IfParameterIsEnum()
{
var methodInfo = typeof(FakeController).GetMethod(nameof(FakeController.ActionWithEnumParameter));
var actionDescriptor = new ActionDescriptor
{
EndpointMetadata = null,
RouteValues = new Dictionary<string, string>(StringComparer.Ordinal)
{
["controller"] = methodInfo.DeclaringType.Name.Replace("Controller", string.Empty)
}
};
var subject = Subject(
apiDescriptions: new[]
{
ApiDescriptionFactory.Create(actionDescriptor, methodInfo, groupName: "v1", httpMethod: "POST",
relativePath: "resource",
parameterDescriptions: new[]
{
new ApiParameterDescription
{
Name = "param",
Source = BindingSource.Query,
Type = typeof(string), // The type comes as string
ModelMetadata = ModelMetadataFactory.CreateForType(typeof(IntEnum)),
}
},
supportedResponseTypes: new []
{
new ApiResponseType
{
ApiResponseFormats = new [] { new ApiResponseFormat { MediaType = "application/json" } },
StatusCode = 200,
},
}
)
}
);

var document = subject.GetSwagger("v1");

var operation = document.Paths["/resource"].Operations[OperationType.Post];


Assert.Equal("IntEnum", operation.Responses["200"].Content.First().Value.Schema.Reference.Id);
Assert.Equal("IntEnum", operation.Parameters.First().Schema.Reference.Id);
Assert.Equal(ReferenceType.Schema, operation.Parameters.First().Schema.Reference.Type);
Assert.Equal(3, document.Components.Schemas["IntEnum"].Enum.Count);
}

[Fact]
public void GetSwagger_SetsEnumRef_IfRequestBodyIsEnum()
{
var methodInfo = typeof(FakeController).GetMethod(nameof(FakeController.ActionWithEnumParameter));
var actionDescriptor = new ActionDescriptor
{
EndpointMetadata = null,
RouteValues = new Dictionary<string, string>(StringComparer.Ordinal)
{
["controller"] = methodInfo.DeclaringType.Name.Replace("Controller", string.Empty)
}
};
var subject = Subject(
apiDescriptions: new[]
{
ApiDescriptionFactory.Create(actionDescriptor, methodInfo, groupName: "v1", httpMethod: "POST",
relativePath: "resource",
parameterDescriptions: new[]
{
new ApiParameterDescription
{
Name = "param",
Source = BindingSource.Body,
Type = typeof(string), // The type comes as string
ModelMetadata = ModelMetadataFactory.CreateForType(typeof(IntEnum)),
}
},
supportedRequestFormats: new[]
{
new ApiRequestFormat { MediaType = "application/json" }
},
supportedResponseTypes: new []
{
new ApiResponseType
{
ApiResponseFormats = new [] { new ApiResponseFormat { MediaType = "application/json" } },
StatusCode = 200,
},
}
)
}
);

var document = subject.GetSwagger("v1");

var operation = document.Paths["/resource"].Operations[OperationType.Post];


Assert.Equal("IntEnum", operation.Responses["200"].Content.First().Value.Schema.Reference.Id);
Assert.Equal("IntEnum", operation.RequestBody.Content.First().Value.Schema.Reference.Id);
Assert.Equal(3, document.Components.Schemas["IntEnum"].Enum.Count);
}

[Fact]
public void GetSwagger_SetsDeprecated_IfActionHasObsoleteAttribute()
{
Expand Down
11 changes: 11 additions & 0 deletions test/WebSites/Basic/Controllers/CrudActionsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ public void Patch(int id, [FromBody, Required]IDictionary<string, object> update
public void Delete(int id)
{
}

[HttpGet("status", Name = "GetStatus")]
public void GetStatus(ProductStatus status)
{
}

[HttpPost("status", Name = "GetStatus")]
public ProductStatus PostStatus([FromBody] ProductStatus status)
{
return status;
}
}

public enum ProductStatus
Expand Down

0 comments on commit 1b89744

Please sign in to comment.