-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Support Deprecation Metadata in the API Explorer #43493
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
Comments
Is there a reason that the For MVC controllers, is it possible to check for the apiDescription.CustomAttributes().OfType<ObsoleteAttribute>().Any(); |
Yes - there is a reason. Not every library needs or uses OpenAPI. API Versioning does not directly reference or otherwise specifically care about OpenAPI. OpenAPI document generators like Swashbuckle and NSwag use the metadata provided by the API Explorer. API Versioning exposes this metadata to them (and anyone else) without any direct knowledge or dependency on OpenAPI. Is an attribute is possible - yes; however, you're missing the point. Using the [ApiVersion(0.9, Deprecated = true)]
[Route("[controller]")]
public class LegacyController : ControllerBase { } This is just one example of how it can be done. API Versioning also doesn't care about specific attributes. Using attributes are just one way that the versioning metadata can be expressed. The problem with using an attribute - any attribute, such as There are potential use cases outside of OpenAPI. Looking back at how the API Explorer was brought into the ASP.NET Core world, there are definitely some things that probably should have been done differently. This is how I managed to get |
Honestly, I thought this would be easy win. Since we're on the topic of deprecation, there are other, related pieces of metadata that are not exposed either. Deprecation typically implies that an API will sunset (e.g. go away) at some point, but not necessarily. API Versioning now supports Sunset Policies as defined by RFC 8594. This provides information as to when or if an API will be sunset as well as any related links; for example, an API might have a web page with a publicly stated policy. These not concepts are not mutually exclusive. A deprecated API should have a stated sunset policy, but an API can also have a sunset policy without being deprecated. While it might be possible via an extension, OpenAPI nor any document generator that I know of can provide this type of information today. This type of information, however, is useful for API clients when the onboard. This information can also change on a dime. It's possible to onboard to a supported API and a week later it's deprecated. API Versioning now provides DI extensions for I figured adding numerous metadata bits to the API Explorer would have resistance so I initially didn't think it worth mentioning. Since this appears to be turning into a longer debate and justification, I'll just throw all my cards out on the table. A sunset policy would consist of nothing more than an ISO 8601 date (e.g. |
Yep, the metadata pattern is what motivated us to pursue the more OpenAPI-based approach in the first place. As we examined some of the feedback on features that were missing in ApiExplorer, we realized a lot of them were addressed by more complete OpenApi support. Essentially, switching from a model where an adhoc-ish collection of metadata that we maintain is the contract, to more formally using OpenAPI as the contract. I recognize that this means that these tools now have to take a dependency on OpenAPI, but given that OpenAPI is meant to provide a standard for annotating these RESTful APIs, it makes sense to lean on that instead of continuing to re-invent in our own metadata.
Interesting. Is this information that could be communicated in the |
I understand the motivation, but I'll have to agree to disagree. The foundation of all OpenAPI support in ASP.NET Core, even with Minimal APIs, still relies on API Explorer and I don't see that changing anytime soon. For things that are truly OpenAPI-specific, I think the extension paths that have been added make complete sense. There are several other areas, however, that will feel are disjointed because it requires a combination of some API Explorer and some OpenAPI extensions. The real issue I see with this approach is that is forcing everyone using OpenAPI in the .NET ecosystem to use
Yes - it could most definitely be added as an general extension. That's certainly where it would start, but given that it's based on a now ratified RFC, I think there is a possibility for it to evolve into a standard part of OpenAPI at some point. If using To your point, API Versioning does not derive policy; it can't. Only an API author knows what the policy is. This has long been a gap for APIs. Deprecation is one thing, but how is policy conveyed? When will a deprecated API sunset? Maybe a supported API has a known sunset policy in the future. Maybe an API has none of the above and just wants to advertise to clients here's where you find out what an API's stated policy is. Even knowing where the OpenAPI document is located is not standard. Being able to send API Versioning allows the sunset policy to be defined by API name, API version, or a combination of both. It is emitted any time an API author opts into reporting API version information to clients. This could be for an entire application or just for one or more options.Policies.Sunset( 0.9 )
.Effective( DateTimeOffset.Now.AddDays( 60 ) )
.Link( "policy.html" )
.Title( "Versioning Policy" )
.Type( "text/html" ); I'm still working on putting together comprehensive documentation, but you can get a sense of how it can be consumed by looking at these tests. It's important to know that the capabilities transcend OpenAPI. Documentation is great, but there is no substitution for real-time data. APIs need a way to advertise to their clients when new versions are available or when APIs will sunset without having to rely solely human interaction. If a client onboards to a supported API via an OpenAPI document which later becomes deprecated and will sunset, how would the client know? If API clients configure alerts from their telemetry, they can be notified when these events occur and take appropriate action, if any. |
An interesting issue came up in dotnet/aspnet-api-versioning#920 that is relevant to this issue and I would be relevant to share. Since deprecation isn't directly supported, there needs to be a bridge in Swashbuckle (or somewhere): public class SwaggerDefaultValues : IOperationFilter
{
public void Apply( OpenApiOperation operation, OperationFilterContext context ) =>
operation.Deprecated |= context.ApiDescription.IsDeprecated(); // ← API Versioning extension method
} Now that we have grouping, consider: var builder = WebApplication.CreateBuilder( args );
var services = builder.Services;
services.AddProblemDetails();
services.AddEndpointsApiExplorer();
services.AddApiVersioning()
.AddApiExplorer(options => options.GroupNameFormat = "'v'VVV");
services.AddSwaggerGen( options => options.OperationFilter<SwaggerDefaultValues>() );
var app = builder.Build();
var orders = app.MapApiGroup( "Orders" );
var v1 = orders.MapGroup( "/orders" )
.HasDeprecatedApiVersion( 0.9 )
.HasApiVersion( 1.0 );
v1.MapGet( "/{id:int}", ( int id ) => new Order() { Id = id, Customer = "John Doe" } )
.Produces<Order>()
.Produces( 404 ); No surprise, if you run this in the Swagger UI, things work as expected, which is to say:
If we then, bring in Microsoft.AspNetCore.OpenApi and add v1.MapGet( "/{id:int}", ( int id ) => new Order() { Id = id, Customer = "John Doe" } )
.WithOpenApi()
.Produces<Order>()
.Produces( 404 ); things fall down; specifically: ✅ This happens because It's also worth noting that a API Versioning ensures things work through the API Explorer by fanning out If the direction is an entirely new API and overhaul of what the API Explorer did that is purely OpenAPI focused, I can get onboard with that, but there are significant barriers to achieving parity with how things work today. As an aside, there were previous gaps that were addressed long ago. I believe this is the last hurdle to achieve parity, even if Swashbuckle still doesn't honor them all (which is a separate issue). |
Pretty much agree on everything points you said. It has to rely on API Explorer unless MS replace it with something like Super API Explorer, because generic types are available only during runtime, while OpenAPI is architecturally static thus does not support generic types. And there are many other meta info available only during runtime as well. Technically it is quite easy to add "IsDecprecated" to ApiDescription, just a 5-minute job, And the benefit to tool developers and client application developers is huge, since they get hints/alerts when programming in IDE, while using ObsoleteAttribute has been a convention for .NET developers for over 2 decades. |
Background and Motivation
The API Explorer has been the pinnacle of sharing API metadata across different ASP.NET Core libraries. The concept of a deprecated API exists in a number of different libraries such as ASP.NET API Versioning, Swashbuckle, NSwag, and OpenAPI .NET to name a few. Each library has its own method of describing a deprecated API, without any shared metadata, developers are required to create their own bridges to connect the two.
While not strictly required, it is reasonable to have the existing API Explorer metadata discovery indicate an API is deprecated when the
ObsoleteAttribute
is applied.Proposed API
Usage Examples
Default Behavior
The presence of
ObsoleteAttribute
on a valid action would setApiDescription.IsDeprecated
totrue
.Default Action (Not Deprecated)
Deprecated Action
Non-Action (Ignored)
Deprecated Controller
Non-Action on Deprecated Controller (Ignored)
API Versioning Behavior
The API Versioning extensions for the API Explorer will set
ApiDescription.IsDeprecated
totrue
whena known, deprecated API version is encountered.
Alternative Designs
Minimal APIs have exposed an extension method to set the OpenAPI metadata, but this approach is no different than using an OpenAPI extension in Swashbuckle, NSwag, and so on or simply using OpenAPI .NET directly.
Risks
There are no tangible risks. The default behavior will continue to indicate that an API is not deprecated by default. Library will authors will be required to update this information when appropriate and consumers will be obliged to honor the value when set.
Related Links
The text was updated successfully, but these errors were encountered: