Azure / azure-functions-openapi-extension

This extension provides an Azure Functions app with Open API capability for better discoverability to consuming parties
https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.OpenApi/
MIT License
370 stars 194 forks source link

Does not generate valid OpenApi 3.0.1 spec; mutually exclusive `example` and `examples` elements are both generated. #662

Open djseng opened 2 months ago

djseng commented 2 months ago

Given the function

using System.Net;
using System.Net.Mime;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;

namespace PocApiDescFunction;

public class HttpHelloMe
{
    private readonly ILogger<HttpHelloMe> _logger;

    public HttpHelloMe(ILogger<HttpHelloMe> logger)
    {
        _logger = logger;
    }

    [Function(nameof(HttpHelloMe))]
    [OpenApiOperation(operationId: "Greeting", tags: ["GM"])]
    [OpenApiParameter(name: "name", In = ParameterLocation.Path, Required = true, Type = typeof(string),
        Description = "The name of the person.")]
    [OpenApiResponseWithBody(
        statusCode: HttpStatusCode.OK,
        contentType: MediaTypeNames.Application.Json,
        bodyType: typeof(Hello),
        Description = "It is always a great day to have a great day!",
        Example = typeof(HelloOpenApiExample))]
    [OpenApiResponseWithoutBody(
        statusCode: HttpStatusCode.NotFound,
        Description = "Non alpha name is not allowed.")]
    public IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get",
            Route = "hello/{name:alpha}")]
        HttpRequest req, string name)
    {
        _logger.LogInformation("Going to say GM to {name}.", name);
        return new OkObjectResult(new Hello($"GM, {name}!"));
    }
}

public class HelloOpenApiExample : OpenApiExample<Hello>
{
    public override IOpenApiExample<Hello> Build(NamingStrategy? namingStrategy = null)
    {
        Examples.Add(OpenApiExampleResolver.Resolve("{name=John}", "John appears!", new Hello("GM, John!"), namingStrategy));
        Examples.Add(OpenApiExampleResolver.Resolve("{name=Sandy}", "Sandy appears!", new Hello("GM, Sandy!"), namingStrategy));
        return this;
    }
}

public record Hello(string Message);

outputs

openapi: 3.0.1
info:
  title: OpenAPI Document on Azure Functions
  description: This is the OpenAPI Document on Azure Functions
  version: 1.0.0
servers:
  - url: https://poc-apim-function.azurewebsites.net/api
paths:
  '/hello/{name}':
    get:
      tags:
        - GM
      operationId: Greeting
      parameters:
        - name: name
          in: path
          description: The name of the person.
          required: true
          schema:
            type: string
      responses:
        '200':
          description: It is always a great day to have a great day!
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/hello'
              example: '{"message":"GM, John!"}'
              examples:
                '{name=John}':
                  summary: John appears!
                  value: '{"message":"GM, John!"}'
                '{name=Sandy}':
                  summary: Sandy appears!
                  value: '{"message":"GM, Sandy!"}'
        '404':
          description: Non alpha name is not allowed.
components:
  schemas:
    hello:
      type: object
      properties:
        message:
          type: string