Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support emitting OpenAPI documents in YAML format #58516

Closed
1 task done
john-shika opened this issue Oct 19, 2024 · 4 comments
Closed
1 task done

Support emitting OpenAPI documents in YAML format #58516

john-shika opened this issue Oct 19, 2024 · 4 comments
Assignees
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi
Milestone

Comments

@john-shika
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

I am trying to do configuration OpenApi with YAML format, some research, it can be tricky, because need access to Microsoft.OpenApi document instead of Microsoft.AspNetCore.OpenApi extension, that know is not accessing by public (internal sealed class), must be rewrite entire OpenApi extension with self-version or waiting some feature.

Describe the solution you'd like

I am supposed to try this one, but some restricted access some object classes, warning in my IDE the object classes is internal sealed class, so
I give my idea, in the comment below

public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern = OpenApiConstants.DefaultOpenApiRoute, OpenApiFormat format = OpenApiFormat.Json)
    {
        var options = endpoints.ServiceProvider.GetRequiredService<IOptionsMonitor<OpenApiOptions>>();
        return endpoints.MapGet(pattern, async (HttpContext context, string documentName = OpenApiConstants.DefaultDocumentName) =>
            {
                var documentService = context.RequestServices.GetKeyedService<OpenApiDocumentService>(documentName);
                if (documentService is null)
                {
                    context.Response.StatusCode = StatusCodes.Status404NotFound;
                    context.Response.ContentType = "text/plain;charset=utf-8";
                    await context.Response.WriteAsync($"No OpenAPI document with the name '{documentName}' was found.");
                }
                else
                {
                    var document = await documentService.GetOpenApiDocumentAsync(context.RequestServices, context.RequestAborted);
                    var documentOptions = options.Get(documentName);
                    using var output = MemoryBufferWriter.Get();
                    using var writer = Utf8BufferTextWriter.Get(output);
                    try
                    {
                        switch (format)
                        {
                            case OpenApiFormat.Json:
                                document.Serialize(new OpenApiJsonWriter(writer), documentOptions.OpenApiVersion);
                                context.Response.ContentType = "application/json;charset=utf-8";
                                await context.Response.BodyWriter.WriteAsync(output.ToArray(), context.RequestAborted);
                                await context.Response.BodyWriter.FlushAsync(context.RequestAborted);
                                break;
                            case OpenApiFormat.Yaml:
                                document.Serialize(new OpenApiYamlWriter(writer), documentOptions.OpenApiVersion);
                                context.Response.ContentType = "text/yaml;charset=utf-8";
                                await context.Response.BodyWriter.WriteAsync(output.ToArray(), context.RequestAborted);
                                await context.Response.BodyWriter.FlushAsync(context.RequestAborted);
                                break;
                            default:
                                throw new ArgumentOutOfRangeException(nameof(format), format, null);
                        }
                    }
                    finally
                    {
                        MemoryBufferWriter.Return(output);
                        Utf8BufferTextWriter.Return(writer);
                    }
    
                }
            }).ExcludeFromDescription();
    }

this is method yoink origin method from Microsoft.AspNetCore.OpenApi.Extensions

Additional context

Oh Yap, I am trying added Bearer JWT from samples in Microsoft.OpenApi, it works but must be complicated because need security Bearer for each-endpoint, make some extensions and parsing tags instead of Authorize attribute class because there not parsing and exists in OpenApiDocument, trigger some tag have JWT and added security bearer for specific endpoints, but this is bad look

ex. code like this one

    [HttpGet("validate")]
    [Tags(TagNames.BearerJwt, TagNames.RoleAdmin, "Auth")]
    [EndpointSummary("VALIDATE_USER")]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "Admin")]
    [Produces(MediaTypeNames.Application.Json)]
    public async Task<IResult> ValidateToken([FromHeader(Name = "Authorization")] string authorization)
   {
      ...
   }

I must be added Authorize and Tag TagNames.BearerJwt for trigger my extension to create security bearer for specific endpoints, why not added Authorize attribute information in OpenApiDocument so I can create security bearer with easy ways :)

but thanks for reading my problems, and I am appreciating your hard works, If there are any mistakes from me, please forgive me, because this is my first time using Microsoft.AspNetCore.OpenApi.

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Oct 19, 2024
@martincostello martincostello added feature-openapi area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Oct 19, 2024
@captainsafia
Copy link
Member

@john-shika Thanks for filing this issue! It was originally requested in the OpenAPI meta-issue but I never got around to implementing it.

I've opened #58616 with a proposed implementation. Let me know what you think about it?

@captainsafia captainsafia self-assigned this Oct 24, 2024
@captainsafia captainsafia added this to the 10.0-preview1 milestone Oct 24, 2024
@captainsafia captainsafia changed the title AspNetCore OpenApi YAML format support Support emitting OpenAPI documents in YAML format Oct 28, 2024
@ranma42
Copy link
Contributor

ranma42 commented Nov 13, 2024

@captainsafia does this feature request also cover the build-time generation of YAML OpenAPI docs? IIUC #58616 covers the case in which the document is generated/retrieved at runtime, but build-time only supports JSON.

@captainsafia
Copy link
Member

@ranma42 Yep, this is just about runtime. Build-time will be covered as part of #58353 which tracks improving the experience for configuring the build-time generation pipeline overall.

@captainsafia
Copy link
Member

Closing this out for now since support has shipped in .NET 10 Preview 1.

In the meantime, for folks wanting to address this gap, @martincostello has provided an API for this in their OpenApi.Extensions library over at https://github.com/martincostello/openapi-extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi
Projects
None yet
Development

No branches or pull requests

4 participants