Roadmap: ASP.NET API Versioning 6.0 #808
commonsensesoftware
started this conversation in
Show and tell
Replies: 1 comment 2 replies
-
The new requirement that error responses must be in the problem details format seems like a very strange decision, and unfortunately block us from updating. Very few existing web services are going to change their error formats, so I can't fathom the logic behind this. |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The
6.0
version will be a large, evolutionary release for API Versioning. This will be the first release where Project Asp standson its own two feet under the .NET Foundation without any Microsoft branding. There are a bunch of new features and enhancements
coming in this release that should make the juice worth the squeeze. Two new areas that will be supporting API versioning are HTTP
clients and expanded support for advertising API policies. In addition to the new enchancements, the laundry list of open issues
will be burned down.
The first part of the roadmap will be adding a new main branch that reorganizes the structure of the repo to be more
compliant with mono repos. Hopefully, that will make it easier to view, browse, and work with various parts of the codebase. The
existing
master
branch will renamed toms
so it is clear where the older Microsoft-branded content lies.High-Level Items
5.x
for existing packagesPerformance
Although no formal benchmarks have ever be collected for comparison, I've gone back through every square inch of the code and
revisted a number of places that see increased performance improvements. A few of the common uses include:
for
overforeach
where possibleSpan<T>
andReadOnlySpan<T>
where possible.NET 6.0 and beyond will see additional support for optmized features such as
ISpanFormattable
. The .NET Framework targets willcontinue to support .NET 4.5, but will also now include targeting .NET 4.7.2 to take partial advantage of optimizations such as
Span<T>
andReadOnlySpan<T>
.Minimal APIs
API Versioning in ASP.NET Core will now be broken into two parts:
The core HTTP library will provide the foundational routing extensions and support for Minimal APIs. Although you reference all
of ASP.NET Core as a framework, this core library will no longer have any dependencies on MVC. The MVC library will extend upon
the core HTTP library and provide of the functionality you're accustomed to today.
API Explorer support for versioned Minimal APIs is not entirely clear - yet. The API Explorer is currently part of MVC. It is
expected that API Explorer extensions will require MVC Core, if you only intend to use Minimal APIs. This might change in
the future.
Sunset Policies
API Versioning has long supported advertising which API versions are supported and deprecated via the
api-supported-versions
andapi-deprecated-versions
respectively. A key limitation of this support is that it does not indicate when an API version willbe sunset nor what the stated policy is.
API Versioning
6.0
will introduce support for RFC 8594. This will allow anAPI version to indicate when it will disappear for good via the
Sunset
header. This header does not necessarily apply to allAPI versions, it will only apply to the API version that was requested. The sunset policy can include additional information
such as a web page or OpenAPI document. These additional links will conform to Web Linking as defined by
RFC 8288.
These capabilities are useful, not only for instrumented clients, but also for tooling. As an example, an API might
support an
OPTIONS
request to retrieve this information for tooling:This indicates to a client that the requested API version
1.0
will sunset on 4/1/2022. It also provides a link to a publicweb page that outlines the API versioning policy as well as a link to where the OpenAPI document is located.
Sunset policies do not have to have a date. The following scenarios will be supported:
Supporting a sunset policy with links alone enables advertising a stated policy when you don't know when an API version might
actually be sunset, which will be common for the current version of an API.
A new, fluent API will be provided to define a sunset policy. If a sunset policy is defined, it will be emitted through the
existing
IReportApiVersions
service. This service is automatically utilized wheneverApiVersioningOptions.ReportApiVersions
is set to
true
orReportApiVersionsAttribute
is applied.API Version-Aware HTTP Clients
For many years, it has been causally asked how to take advantage of the API versioning information in HTTP clients. While there
were a few interesting cases, it was always low on the priority list and never came to fruition. The rework of the project and
the introduction of Sunset Policies necessitate re-evaluation.
Starting in API Versioning
6.0
, there will be a new client-side library that will introduce anIApiVersionWriter
servicethat understands how to write API versions into each HTTP request automatically. For parity, you will be able to compose
multiple writers via
ApiVersionWriter.Combine
, even though that seems unnecessary. A big part of what will make thisfunctionality possible is breaking out the core API Versioning functionality, such as
ApiVersion
, into a common abstractionslibrary. The same parsing, formatting, and so on will now be available for HTTP clients.
HTTP client handlers will also support
IApiNotification
, which will provide a hook to notify your client when:If you are using
Microsoft.Extensions.Logging
, then:If you're using some other logging framework, you can replace the default
IApiNotification
service with whatever you want.The
HttpClient.GetApiInformationAsync
extension method will be provided to request API information from an endpoint usingan
OPTIONS
request. This will have the same semantics as the example given above for Sunset Policies. The use cases arelimited (ex: tooling) and the out-of-the-box implementation is prescriptive.
OData
OData 8.0 has been out for a while, but it is significant departure from its previous implementation. It also includes
protocol-level changes for OData 4.01, which some people may not even realize. This will ultimately result in a rewrite of
the entire implementation. API Versioning
6.0
will provide support for OData 8.0 as well as a target for .NET 6.0.OData provides limited support for the API Explorer and OpenAPI documentation. API Versioning has supported extensive
support for OData-specific API features, such as query options. Some people, however, are interested in using the
query capabilities of OData without ultizing the whole stack. Today, this results in a poor experience that turns into
thousands of API parameters. This release will take a deeper look at how to support query parameters in non-OData
controllers.
Breaking Changes
A lot of changes need to occur as part of the project evolution. I'm very cognizant of the pain breaking changes can
cause, thus my goal is to make one large change and put it behind us for good. For the most part, you can expect the
changes to largely be a new package identifier and different namespaces. It is entirely possible that you may update
those and find the code to be nearly identical. The mileage will vary depending on your level of customization, but
you can expect the changes to be trivial in most cases.
In no particular order, here are some of the most significant breaking changes you can expect:
Package Identifiers
Beginning in API Versioning
6.0
and beyond, the NuGet package identifiers will use theAsp.Versioning.*
prefix. Theolder
Microsoft.*
prefixes will only be supported for servicing. The expected list of package identifiers is:Namespaces
As the project is no longer part of Microsoft, all namespaces will become
Asp.Versioning.*
. I thought long and hard aboutthis, but it doesn't make sense to keep using
Microsoft.*
when things don't line up. Furthermore, what namespace shouldall new code live under? Continuing to use the
Microsoft
namespace seemed wrong. An interesting benefit, however, isthat using
Api.Versioning.*
allows for more consistency across the ASP.NET Web API and Core implementations. The existingdifferences in library namespaces for shared code often led to a lot of ugly compiler directives. For ease of use,
extension methods will continue to live in the namespace they correspond to.
API Version
The format and default implementation will not change, but parsing will be broken apart. People have often asked about using
a custom
ApiVersion
. This has always been possible, but it was not easy to do. A big reason why it was not easy isbecause the type was coupled with parsing. The original idea was to have data type parsing analogous to
int.Parse
, butit ultimately didn't pan out that way.
A new
IApiVersionParser
service will be introduced to support this capability. For .NET targets that support it, parsingwill also support accepting
ReadOnlySpan<char>
.ApiVersion.Parse
andApiVersion.TryParse
will be removed, but arereplaced by
ApiVersionParser.Default
, which will provide a default implementation that is parallel to today.Some addition features include relaxed rules for
ApiVersion.Status
and constructing API versions from numbers (e.g.double
)as opposed to magic strings. For example,
new ApiVersion(1.0)
ornew ApiVersion(2.1, "Beta")
.The one breaking change to
ApiVersion
I believe will be a welcomed one.ApiVersion.GroupVersion
in .NET 6.0 and beyondnow will be represented as
DateOnly
.DateOnly
accurrately represents how a group version or date version was alwaysmeant to be, but couldn't without introducing its own type due to the design of
DateTime
. The .NET Standard and .NETFramework representions will continue to use
DateTime
.API Version Reader
IApiVersionReader.Read
will now returnIReadOnlyList<string>
instead ofstring?
. There are a few reasons for this change.First, the Null Mistake is removed as an empty list is completely acceptable. Second, it was entirely possible for a particular
reader implementation to return more than one value. Consider that
?api-version=1.0&api-version=2.0
would return both1.0
and2.0
. In today's implementation that would instead throw an exception that would have to be handled. This becomes problematicfor the server to correctly report the response to the client. This really isn't exceptional, it's just an invalid client
request. This change will make it easier to collect and report that behavior. Finally,
ApiVersionReader.Combine
enabledcombining different types of readers through composition. Readers for different parts of a request are even more likely to
return different values. Refactoring to return a list makes it very simple to return all of the raw API versions provided
without any exceptions and regardless of where they were read from.
API Version Reporting
IReportApiVersions.Report
will now accept the entire HTTP response as opposed to just the headers. Accepting only theheaders was an over-normalization that wasn't really necessary. Additional information was also necessary to support
Sunset Policies. The
Report
overload that acceptsLazy<ApiVersionModel>
will be removed as it's no longer usedor necessary.
API Version Model Extensions
Most of the extension methods related to retrieving an
ApiVersionModel
have been supplanted by the new extension methodGetApiVersionMetadata()
. TheGetApiVersionModel()
extension method, for example, was a shortcut forGetApiVersionModel(ApiVersionMapping.Explicit)
. A new type -ApiVersionMetadata
- has been introduced that unifies themetadata implementation across ASP.NET frameworks. In most cases, this information was retrieved from
HttpActionDescriptor
in ASP.NET Web API andActionDescriptor
in ASP.NET Core. In ASP.NET Core, this information isnow stored in the
ActionDescriptor.EndpointMetadata
andEndpoint.Metadata
collections (depending on context).This is the old to new mapping:
GetApiVersionModel(ApiVersionMapping) → GetApiVersionMetadata()
GetApiVersionModel() → ApiVersionMetadata.Map(ApiVersionMapping.Explicit)
MappingTo(ApiVersion) → ApiVersionMetadata.MappingTo(ApiVersion)
IsMappedTo(ApiVersion) → ApiVersionMetadata.IsMappedTo(ApiVersion)
Error Response Provider
The
IErrorResponseProvider
service has been the hook to provide custom error responses. Problem Details(RFC 7807) had just been ratified when this project started and wasn't
part of ASP.NET. ASP.NET Core eventually added first class support for Problem Details and
IErrorResponseProvider
had an adapter implementation for alignment. Now that Problem Details are the de factor method for error reporting,
it no longer makes sense to keep
IErrorResponseProvider
around, so it has been removed.ASP.NET Web API does not provide such a capability so the implemetation from ASP.NET Core has been backported. In addition,
the ASP.NET Core
ProblemDetailsFactory
is an abstract class that is within MVC Core. To maintain separation from MVC,the
IProblemDetailsFactory
interface will be added that can be used in Minimal APIs and an automatic adapter will beprovided for MVC so that developers do not need two implementations if/when they customize things. The ASP.NET team
is tracking work to make the use of
ProblemDetails
consistent so things might merge in the .NET 7.0 release.ProblemDetails.Type
is supposed to be a URI. For backward compatibility, the existing error codes will be emitted asthe
Code
extension. The detailed error message in ASP.NET Web API will be emitted as theError
extension.Routing Behaviors
The first big change is that legacy, convention-based routing with
IActionSelector
will be dropped. Limitations inthe original ASP.NET Core routing design caused a number of issues and inconsistencies, which were resolved when
Endpoint Routing was introduced. The only real reason to keep it around was due to OData until it finally supported
Endpoint Routing as well. Certain response scenarios such as
405
or415
were difficult to support. Given thematurity of Endpoint Routing, I don't think it's worth the effort to continue supporting
IActionSelector
in thecontext of API Versioning. If anyone really needs it, the code still exists in the repo history for people to use in
their own solutions or it can be supported through a community extension.
The changes to routing implementation are more of an enhancement, but it will result in some behavioral changes that
might be unexpected. ASP.NET Core, in particular, requires these changes to address other open issues. The routing logic
will be updated to properly return a response for
404
,405
, and415
.415
will now be properly reported whenversioning by media type without requiring custom error reporting as is the case today.
Due to the way routing works in ASP.NET Core, it is no longer possible to always report
400
when an API versioncould be matched, but doesn't. In most cases, what would have been
400
will now return404
,405
, or415
. Insome of these cases it is also not possible to add
ProblemDetails
. Where possible,400
and404
will returnProblemDetails
, but it is not always guaranteed. Improvements to ASP.NET Core in .NET 7.0 might alleviate that.ASP.NET Web API will have parity with these behaviors, even though the routing system is completely different. API Versioning
has more control over the routing system in Web API so for the most part the only thing that will change is the status code.
What happens when an API version could match, but doesn't has always been a bit of a gray area. The general consensus seems
to be that developers don't care because it's a client error or they expect it to be
404
. These revised rules will nowreturn
404
more likely than not.A few other breaking changes are fairly minor. The existing
UseApiVersioning()
middleware will be removed. It never didanything except setup the
IApiVersioningFeature
in the current request. API Versioning doesn't have any real middlewareso there is no sense it keeping it around. It also removes an unnecessary level of indirection out of the request pipeline.
Configuration
Support for Minimal APIs and OData in ASP.NET Core required some changes to how services are configured in an application.
A new
IApiVersioningBuilder
interface has been added which all API Versioning related extensions will hang off of. This willalso help address extension method naming conflicts and scenarios where you might forget to register another set of required
services. If you referenced and enabled everything supported by API Versioning, then your configuration might look like:
In Closing
The changes to response error codes and
ProblemDetails
for errors are the most concerning in my opinion. These affect serverresponses over the wire that clients might depend on. Honestly, that seems unlikely because these responses are all errors
that indicate the client doesn't know how to call the server API. Nevertheless, it's a breaking change that isn't easily
addressed. When it comes to swapping the implementation, how do you version the versioning behavior? This would only affect
existing services that want to upgrade. New services will simply have the new behavior. Perhaps this is a non-issue. Services
that must maintain the current behaviors simple do not upgrade to newer versions of the libraries until the old APIs
are sunset.
What's your take? I'd love to hear more from the community. What else do you want to see happen? Are there features
that I've missed. Are there changes you think are unacceptable? Do you want different names? How would you like to
engage on these topics? Discussions, Discord, Slack, online meeting, an Ask Me Anything (AMA)? I doubt there
will be a universal consensus, but I definitely want feedback and input from the community. Provide your thoughts
below.
I don't have an official release date scheduled as there are still some unknowns, but the in-flight work is now available in
the new main branch. As soon as all of the .NET Foundation tasks are complete, a new build server is configured,
and code signing is setup, I'll begin queuing up preview releases.
Chris (@commonsensesoftware)
The API Versioning Team
Beta Was this translation helpful? Give feedback.
All reactions