azure-functionsopenapiswashbuckle

Need to show dropdown in Azure Function Http Trigger with Open API Post Request


I need to show the options Hostname1, Hostname2 and Hostname3 in the below dropdown, but it is displaying options 0, 1 and 2. The code is written in Azure Function Http Trigger with Open API, .NET 6 Version.

enter image description here

Below is the code I am using:

Azure Function:

public enum Hostname
{
    Hostname1,
    HostName2,
    HostName3,
}

public class OpenAPIFunction
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<OpenAPIFunction> _logger;

    public OpenAPIFunction(ILogger<OpenAPIFunction> log, IHttpClientFactory httpClientFactory)
    {
        _logger = log;
        _httpClient = httpClientFactory.CreateClient();
    }

    [FunctionName("OpenAPIFunction")]
    [OpenApiOperation(operationId: "Run", tags: new[] { "name" })]
    [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
    [OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = true, Type = typeof(Hostname), Description = "The **Name** parameter. Allowed values: `Hostname1`, `HostName2`, `HostName3`")]
    [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]
    public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", "post", Route = null)] Hostname req)
    {
        _logger.LogInformation("C# HTTP trigger function processed a request.");

        //string name = req.Query["name"];

        //string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        //dynamic data = JsonConvert.DeserializeObject(requestBody);
        //name ??= data?.name;

        string responseMessage = string.IsNullOrEmpty("")
            ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
            : $"Hello, {""}. This HTTP triggered function executed successfully.";

        return new OkObjectResult(responseMessage);
    }
}

Startup.cs:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen(c =>
        {
            c.SchemaFilter<EnumSchemaFilter>();
        });
    }
}

Filter:

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema openApiSchema, SchemaFilterContext schemaFilterContext)
    {
        if (schemaFilterContext.Type.IsEnum)
        {
            openApiSchema.Type = "string";
            openApiSchema.Enum.Clear();
            var enumValues = Enum.GetNames(schemaFilterContext.Type);

            foreach (var enumValue in enumValues)
            {
                openApiSchema.Enum.Add(new OpenApiString(enumValue));
            }
        }
    }
}

Project File:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="1.0.0" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.2.0" />
    <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.5.0" />
    <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

I have tried following this thread but unable to figure out what I am doing wrong. Any help would be appreciated.


Solution

  • Add [JsonConverter(typeof(StringEnumConverter))] in Enum.

    [JsonConverter(typeof(StringEnumConverter))]
    public enum Hostname
    {
        Hostname1,
        HostName2,
        HostName3,
    }
    

    I have below code in OpenAPIFunction file.

    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
    using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
    using Microsoft.Extensions.Logging;
    using Microsoft.OpenApi.Models;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;
    
    namespace _78461112
    {
        public class OpenAPIFunction
        {
            private readonly HttpClient _httpClient;
            private readonly ILogger<OpenAPIFunction> _logger;
    
            public OpenAPIFunction(ILogger<OpenAPIFunction> log, IHttpClientFactory httpClientFactory)
            {
                _logger = log;
                _httpClient = httpClientFactory.CreateClient();
            }
    
            [FunctionName("OpenAPIFunction")]
            [OpenApiOperation(operationId: "Run", tags: new[] { "name" })]
            [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
            [OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = true, Type = typeof(Hostname), Description = "The **Name** parameter. Allowed values: `Hostname1`, `HostName2`, `HostName3`")]
            [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]
            public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req)
            {
                _logger.LogInformation("C# HTTP trigger function processed a request.");
    
                string name = req.Query["name"];
    
                string responseMessage = string.IsNullOrEmpty(name)
                    ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                    : $"Hello, {name}. This HTTP triggered function executed successfully.";
    
                return new OkObjectResult(responseMessage);
            }
        }
        [JsonConverter(typeof(StringEnumConverter))]
        public enum Hostname
        {
            Hostname1,
            HostName2,
            HostName3,
        }
    }
    

    .csproj-

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <AzureFunctionsVersion>v4</AzureFunctionsVersion>
        <RootNamespace>_78461112</RootNamespace>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
        <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="2.0.0-preview2" />
        <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.4.0" />
        <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
      </ItemGroup>
      <ItemGroup>
        <None Update="host.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="local.settings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
          <CopyToPublishDirectory>Never</CopyToPublishDirectory>
        </None>
      </ItemGroup>
    </Project>
    

    I am able to get the hostnames in the dropdown.

    enter image description here

    enter image description here

    enter image description here