dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.1k stars 9.91k forks source link

Support XML-based OpenAPI docs for minimal APIs #39927

Open captainsafia opened 2 years ago

captainsafia commented 2 years ago

Is there an existing issue for this?

Describe the bug

Swashbuckle currently supports reading the XML doc string associated with an action's method to derive the description, summary, example, etc for an action.

We need to add similar support for minimal endpoints where the documentation might be on a referenced method group or (maybe) on a Map* invocation.

Expected Behavior

/// <summary>
/// This is a foo.
/// </summary>
string GetFoo() => "This is a test";

Should resolve the correct summary info.

ghost commented 2 years ago

Thanks for contacting us.

We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

jvetter713 commented 2 years ago

I feel this is a very important feature. Minimal Web API's are awesome but if we cannot use comments for use with Swagger, they lose their appeal. Please make this happen.

LeoJHarris commented 2 years ago

Make minimal API's even better with comments 👍 must have feature.

mholec commented 2 years ago

I consider this functionality unnecessary. Given the way REST APIs are created and the constant proliferation of approaches like microservices and API gateways, generating documentation in general makes no sense. The documentation generated falls short of the quality of the specification and reflects implementation errors. Generated documentation is unusable in practice for automation, mocking and testing. The specification first approach has been a trend for several years.

t4apps commented 2 years ago

The Open API documentation can be imported directly into Azure APIM (public facing). It makes a lot of sense.

andrewlock commented 1 year ago

Just FYI, this already works, as long as you

That last point is the biggest sticking point - it would be great if you could use lambdas too, but at least this partially works 🙂

One observation (I'm not sure if it's a bug or expected behaviour). If you use WithOpenApi(), it wipes out any existing documentation of the parameters that comes from XML

ghost commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

JHorvath-MaxetaTech commented 1 year ago

As far as feedback goes, 100% yes please implement this. We just started to move all our old Controller based APIs to new Minimal APIs and immediately realized none of the documentation was coming across in the swagger page. HUGE let-down! This is super important for public facing APIs, allowing developers to easily understand and consume REST services without the need for separate documentation.

pepperpark commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Five more comments and it will be moved to the .NET 9 Planning? :-D

captainsafia commented 1 year ago

Five more comments and it will be moved to the .NET 9 Planning? :-D

lol trust me i feel this way about some favorite issues of mine too

To provide some more context here, at the moment, support for XML docs in OpenAPI isn't supported in-framework by ASP.NET. Instead, you're probably getting the functionality from whatever package you're using to render the Swagger UI and produce the OpenAPI JSON/YML document (usually NSwag or Swashbuckle for most people).

This issue is tracking making integration of XML docs automatic for minimal APIs that leverage WithOpenApi. It falls into the category of features like https://github.com/dotnet/aspnetcore/issues/44232 and https://github.com/dotnet/aspnetcore/issues/39761 where the goal is to make sure that more concepts from your code get funneled into OpenAPI documentation without you having to interfere as much (e.g. enable XML integration in options or document the OpenAPI security definitions yourself).

This feature has a lot of up-votes, which is one of the indicators we use for prioritization (see the docs on how we do milestone planning).

So if these types of features will be helpful to you, giving the main issue an upvote is a great way to help identify which issues are important. Especially for OpenAPI, where TBH, there's a lot of L-XL sized issues that are one our bucket list.

LMK if you have any other feedback/questions.

BTW: I have made of prototype of built-in XML support so there has been some effort applied in this area already.

MNF commented 1 year ago

@andrewlock, could you please point to an example where minimal api generates swagger including xml comments?

Lonli-Lokli commented 1 year ago

@MNF you can check https://github.com/dotnet/aspnet-api-versioning/tree/main/examples/AspNetCore/WebApi/MinimalOpenApiExample

captainsafia commented 1 year ago

@Lonli-Lokli It looks like the example that you provided showcases OpenAPI + Minimal API + API versioning. This blog post summarizes the XML-specific stuff.

captainsafia commented 5 months ago

Automagic support for this will be included as part of the built-in OpenAPI document generation (https://github.com/dotnet/aspnetcore/issues/54598).

Likely not as part of the feature set coming out with preview4 but hopefully before .NET 9 GA.

image

KristofferStrube commented 5 months ago

There isn't a set standard for how documentation like summaries, remarks, returns, and examples should be supplied when XML documentation is included in the generated document as it depends on how the Open API Spec is consumed. The most common way to consume the specification is through Swagger UI which supports descriptions in HTML format for the different endpoints, their return value, the different route parameters, and post-bodies.

When writing XML Documentation we can add extra child tags that convey extra semantic meaning like the following:

/// <summary>
/// Gets a new soft <see cref="Cat" />.
/// </summary>
Cat GetSoftCat() => new("Soft Kittie");

Out of the box, the above would not render a correct link to the Cat model in place of the <see/> tag, but we could look up the generated URI Fragment i.e. #model-Cat and replace the <see /> tag with an anchor to that fragment path. This would be nice as many use see references in their XML Documentation.

Another nice feature of XML Documentation that can be used to minimize repetition of phrases in similar descriptions is the <inheritdoc/> tag.

/// <summary>
/// Gets a new happy <see cref="Cat" />.
/// </summary>
/// <returns>
/// Returns a new <see cref="Cat" /> instance.
/// </returns>
Cat GetHappyCat() => new("Happy Kittie");

/// <summary>
/// Gets a new soft <see cref="Cat" />.
/// </summary>
/// <returns>
/// <inheritdoc cref="GetHappyCat" path="/returns" />
/// </returns>
Cat GetSoftCat() => new("Soft Kittie");

When XML documentation is exported it doesn't resolve these inheritdoc references meaning that the consumer needs to find out what has to be placed in its place. So, if we want to support the <inheritdoc/> tag when generating the descriptions we need to build a method for resolving any potential chain of <inheritdoc/> tags. There exist multiple OSS solutions for this already, but it essentially just consists of building a DAG of the references and filling them in from the end.

captainsafia commented 1 month ago

Hi all!

I wanted to share some updates in this workstream as we get closer to .NET 9 RCs and beyond. Here's the TL;DR:

The extended edition for those who care about it:

The long-term plan at the moment is to ship a source generator in-the-box with Microsoft.AspNetCore.OpenApi that statically analyzes the code for XML comments at build-time and emits a IOpenApiTransformer definitions to the compilation that apply these discovered annotations to the document model.

Doing the discovery work at compile-time allows us to take advantage of pre-existing APIs in Roslyn and in DocFX for discovering XML comments and mapping them to types which lends itself well to accuracy/completeness in the model since these APIs have had some battle-testing in the form of their integrations in Visual Studio QuickInfo and the .NET API docs on docs.microsoft.com.

As for the delay in release, I want to take some time to polish the implementation instead of rushing to ship something in .NET 9 GA that will be incomplete/not land well.

My plan at the moment is to ship a preview-level package of the XML support out of the AspLabs repo for .NET 9 and target this for official release as part of .NET 10. I think this strikes a good balance between giving those eager to try the feature the change to take advantage of it in .NET 9 and gives more bandwith to iterate and land on the right thing for an LTS release.

So yeah....I wish I had better news to share 😅 but I hope this helps us make progress towards resolving this long-standing feature request once and for all.

If you have any questions about the implementation details, let me know. I hope to get the preview code out once action on the main Microsoft.AspNetCore.OpenApi work has slowed.

bkoelman commented 2 weeks ago

The long-term plan at the moment is to ship a source generator in-the-box...

What's great about ASP.NET is that many built-in framework components/services can be replaced with custom implementations, which is what third-party libraries are doing all the time. As a result, a rich ecosystem has emerged. The new OpenAPI integration in ASP.NET doesn't adhere to that design philosophy. Instead of being able to plug in alternate implementations, all that's provided are "fix-up-afterwards" extensibility points (the transformers). Solutions like this paint third-party and framework developers into a corner: instead of plugging in customized behavior, they need to implement additional components that first "undo" the built-in behaviors at runtime and then recreate or fix things up as needed. That's brittle and kills performance.

And using a source generator, as proposed here, makes it impossible to customize the experience (because source generators can't depend on other source generators, and third-party renderers can no longer depend on runtime information). This isn't good enough. NSwag and Swashbuckle are widely used because they're very extensible and customizable. Instead of using a source generator, the tooling should scan the assembly.xml file and populate ApiExplorer, which would enable third-party libraries to integrate.

captainsafia commented 2 weeks ago

Instead of being able to plug in alternate implementations

I think it depends on what you mean by alternate implementations here...

The goal of the OpenAPI integration is to present information that ASP.NET Core understands about the binding/response serialization behavior of APIs in an application in a way that is compliant with the OpenAPI spec.

In that sense, its purely a presentation layer and the things you want to extend/customize are the framework abstractions that end up influencing the binding/metadata rules (IEndpointMetadataProvider, InputFormatter, OutputFormatter, etc.)

And using a source generator, as proposed here, makes it impossible to customize the experience (because source generators can't depend on other source generators, and third-party renderers can no longer depend on runtime information).

What kind of customizations to the XML documentation implementation are you looking to make/influence?

the tooling should scan the assembly.xml file and populate ApiExplorer, which would enable third-party libraries to integrate.

ApiExplorer is the abstraction layer that allows framework implementations to describe the parameter binding and response serialization behavior of their implementation, which ends up influencing the resulting Open API document. ApiExplorer isn't the abstraction layer for exposing information that is actually inert to the behavior of the framework. For example, endpoint descriptions and tags are represented using endpoint metadata, and not as first-class properties in ApiExplorer for this very reason.

Now, there's a separate discussion to be had about whether or not it makes sense to expose the information derived XML docs on types via the source generator in some other runtime API, but I'm not convinced that ASP.NET Core is the right place for an abstraction like that given it has no direct relationship to web APIs.

bkoelman commented 2 weeks ago

I realize using ApiExplorer is not the right terminology. Instead, I should have referred to MVC-based extensibility such as IEndpointMetadataProvider. That's where I'd like the documentation to end up. So that a custom IActionDescriptorCollectionProvider can modify it.

The thing is that summary and description in OpenAPI are the places to express human-friendly information that can't be expressed in the OAS structure itself. The use of .NET attributes enable API developers to indicate intent. From those, documentation can be generated to make API consumers aware of how to use it. Examples:

What's the objection against ASP.NET storing XML doc-comments in the endpoint descriptions, instead of emitting source code?

If the source generator is going to stay, is there a way for a library to deactivate it?