Skip to content

Commit

Permalink
Added tests to demonstrate declaring enums in requests. And updated O…
Browse files Browse the repository at this point in the history
…penAPI to shows values for all enums. Closes #42
  • Loading branch information
jezzsantos committed Jul 27, 2024
1 parent c218c3d commit 70eb23c
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/src/.idea/.idea.SaaStack/.idea/markdown.xml
10 changes: 10 additions & 0 deletions src/ApiHost1/Api/TestingOnly/TestingWebApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ public async Task<ApiPostResult<string, FormatsTestingOnlyResponse>> FormatsRoun
});
}

public async Task<ApiPostResult<string, StringMessageTestingOnlyResponse>> GeneralEnumPost(
PostWithEnumTestingOnlyRequest request, CancellationToken cancellationToken)
{
await Task.CompletedTask;
return () =>
new PostResult<StringMessageTestingOnlyResponse>(
new StringMessageTestingOnlyResponse { Message = $"amessage{request.AnEnum}" },
"alocation");
}

public async Task<ApiEmptyResult> GetInsecure(
GetInsecureTestingOnlyRequest request, CancellationToken cancellationToken)
{
Expand Down
33 changes: 33 additions & 0 deletions src/Infrastructure.Web.Api.IntegrationTests/GeneralApiSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#if TESTINGONLY
using System.Net;
using FluentAssertions;
using Infrastructure.Web.Api.Operations.Shared.TestingOnly;
using IntegrationTesting.WebApi.Common;
using JetBrains.Annotations;
using Xunit;

namespace Infrastructure.Web.Api.IntegrationTests;

[UsedImplicitly]
[Trait("Category", "Integration.API")]
[Collection("API")]
public class GeneralApiSpec : WebApiSpec<ApiHost1.Program>
{
public GeneralApiSpec(WebApiSetup<ApiHost1.Program> setup) : base(setup)
{
}

[Fact]
public async Task WhenGetError_ThenReturnsError()
{
var result = await Api.PostAsync(new PostWithEnumTestingOnlyRequest
{
AnEnum = TestEnum.Value1,
AProperty = null
});

result.StatusCode.Should().Be(HttpStatusCode.Created);
result.Content.Value.Message.Should().Be("amessageValue1");
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#if TESTINGONLY
using System.Text.Json.Serialization;
using Infrastructure.Web.Api.Interfaces;

namespace Infrastructure.Web.Api.Operations.Shared.TestingOnly;

/// <summary>
/// Tests the use of enums in the request
/// </summary>
[Route("/testingonly/general/enum", OperationMethod.Post, isTestingOnly: true)]
public class PostWithEnumTestingOnlyRequest : IWebRequest<StringMessageTestingOnlyResponse>
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public TestEnum? AnEnum { get; set; }

public string? AProperty { get; set; }
}

public enum TestEnum
{
Value1,
Value2,
Value3
}
#endif
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Common.Extensions;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
Expand All @@ -22,12 +20,7 @@ public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
var declaringType = parameterInfo.Member.DeclaringType;
if (declaringType.IsAnnotatable())
{
if (parameter.In == ParameterLocation.Path
|| parameterInfo.GetCustomAttribute<RequiredAttribute>().Exists())
{
parameter.Required = true;
}

parameter.SetRequired(parameterInfo);
parameter.SetDescription(parameterInfo);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.MemberInfo.Exists())
{
// we deal with each of the properties of a schema component
var member = context.MemberInfo;
var declaringType = member.DeclaringType;
if (declaringType.IsAnnotatable())
{
// we only deal with each member of a request and responses types
schema.SetDescription(member);
}

Expand All @@ -30,17 +30,18 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context)

if (context.ParameterInfo.Exists())
{
// we deal with parameters in the DataAnnotationsParameterFilter , not here
// Parameters are dealt with in the DataAnnotationsParameterFilter , not here
return;
}

// we deal with other schemas in general
if (context.Type.IsAnnotatable())
{
// we deal with the schema component
var requestDto = context.Type;
var properties = requestDto.GetProperties();
foreach (var property in properties)
{
// we have to add all required properties to the request collection
if (property.IsPropertyRequired())
{
var name = property.Name.ToCamelCase();
Expand All @@ -53,5 +54,10 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context)
}
}
}

if (context.Type.IsEnum)
{
schema.SetEnumValues(context.Type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Reflection;
using Common.Extensions;
using Infrastructure.Web.Api.Interfaces;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

Expand Down Expand Up @@ -37,28 +38,49 @@ public static bool IsPropertyRequired(this PropertyInfo property)

public static void SetDescription(this OpenApiSchema schema, MemberInfo member)
{
var description = member.GetCustomAttribute<DescriptionAttribute>();
if (description.Exists())
var descriptionAttribute = member.GetCustomAttribute<DescriptionAttribute>();
if (descriptionAttribute.Exists())
{
if (description.Description.HasValue())
if (descriptionAttribute.Description.HasValue())
{
schema.Description = description.Description;
schema.Description = descriptionAttribute.Description;
}
}
}

public static void SetDescription(this OpenApiParameter parameter, ParameterInfo parameterInfo)
{
var description = parameterInfo.GetCustomAttribute<DescriptionAttribute>();
if (description.Exists())
var descriptionAttribute = parameterInfo.GetCustomAttribute<DescriptionAttribute>();
if (descriptionAttribute.Exists())
{
if (description.Description.HasValue())
if (descriptionAttribute.Description.HasValue())
{
parameter.Description = description.Description;
parameter.Description = descriptionAttribute.Description;
}
}
}

public static void SetEnumValues(this OpenApiSchema schema, Type type)
{
var names = Enum.GetNames(type).ToList();
schema.Enum.Clear();
schema.Type = "string";
schema.Format = null;
foreach (var name in names)
{
schema.Enum.Add(new OpenApiString(name));
}
}

public static void SetRequired(this OpenApiParameter parameter, ParameterInfo parameterInfo)
{
if (parameter.In == ParameterLocation.Path
|| parameterInfo.GetCustomAttribute<RequiredAttribute>().Exists())
{
parameter.Required = true;
}
}

private static bool IsInRoute(RouteAttribute routeAttribute, string name)
{
var route = routeAttribute.RouteTemplate;
Expand Down

0 comments on commit 70eb23c

Please sign in to comment.