Comments (22)
The first iteration of packages are available. I'm leaving a little burn-in time with a beta release for issues and/or feedback before the official release. I'll be updating the wiki soon.
- Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
- Microsoft.AspNet.WebApi.Versioning.ApiExplorer
- Microsoft.AspNet.OData.Versioning.ApiExplorer
You can use the links to the sample projects above to get started. Thanks to everyone that helped drive this forward.
from aspnet-api-versioning.
Hi guyz !
Just play with versioning and swagger few days ago and here is what I found :
We have to declare :
- 1 Swagger Document per version : Technically we have to configure SwaggerGen Service
- We all version available for a given action : Use Swagger method
DocInclusionPredicate
inside SwaggerGen config service - Enable SwaggerUI middleware and add Endpoint for each version
For DocInclusionPredicate we already have all the api to configure this method because ApiVersionModel
has been built by ApiVersionConvention
:
c.DocInclusionPredicate((docName, apiDesc) =>
{
var model = apiDesc.ActionDescriptor.GetProperty<ApiVersionModel>();
var version = docName;
if (model.IsApiVersionNeutral)
{
return true;
}
else if (model.DeclaredApiVersions.Any())
{
return model.DeclaredApiVersions.Any(_ => _.ToString() == version);
}
else if (model.ImplementedApiVersions.Any())
{
return model.ImplementedApiVersions.Any(_ => _.ToString() == version);
}
return false;
});
For other points, we can't use that because ApplicationModel hasn't been executed yet but to build SwaggerDoc and SwaggerEndpoint we just have to know all version available into our application not necessarily which action is available in a specific version
Example of code to configure swagger doc and endpoint :
app.UseSwaggerUI(c =>
{
foreach (var version in versions)
{
c.SwaggerEndpoint($"/swagger/v{version}/swagger.json", $"V{version} Docs");
}
});
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
foreach (var version in versions)
{
c.SwaggerDoc($"v{version}", new Info { Title = $"Sample service v{version}", Version = $"v{version}" });
}
c.DocInclusionPredicate((docName, apiDesc) =>
{
//implem is above
...
});
});
from aspnet-api-versioning.
Or like this
options.DocInclusionPredicate((docName, apiDesc) =>
{
var model = apiDesc.ActionDescriptor.GetProperty<ApiVersionModel>();
switch (model)
{
case ApiVersionModel _ when model.IsApiVersionNeutral: return true;
case ApiVersionModel _ when model.DeclaredApiVersions.Any():
return model.DeclaredApiVersions
.Any(apiVersion => apiVersion.ToString() == docName);
case ApiVersionModel _ when model.ImplementedApiVersions.Any():
return model.ImplementedApiVersions
.Any(apiVersion => apiVersion.ToString() == docName);
default: return false;
}
});
from aspnet-api-versioning.
For those following the thread, there is now an end-to-end working Web API Swagger Sample. Now that there are working examples for ASP.NET Core and Web API, I'm convinced the work here is all in the API explorer. There are a few conveniences that could be provided API versioning, but I don't think I should own them.
In my conversations with the ASP.NET team, they still looking to take the core abstractions from here and roll them into the platform. The work has been delayed so I can't say when that will happen. When it does finally happen, it will be easier for Swagger/Swashbuckle libraries to provide some of these capabilities directly out-of-the-box.
The current build is alpha quality. The majority of the remaining work will be testing. I won't release anything official until the quality bar is high. However, since so many of you have been clamoring for this feature and have patiently waited for months, I'm willing to put out an alpha package for you to play with. No guarantee that nothing else will change, but I'm pretty confident little will change to the public API surface. Let me know your reaction.
Thanks
from aspnet-api-versioning.
I've added full versioning support to the ASP.NET API Boilerplate project template. You can now use dotnet new
to create a project and optionally enable or disable Swagger and/or ASP.NET API Versioning (Both options are turned on by default) as well as a dozen other settings.
from aspnet-api-versioning.
Awesome! I'm sure this will help folks stitch things together very quickly. Thanks for putting in the work and sharing. :)
from aspnet-api-versioning.
If it helps, when I currently use this and Swagger, Swagger outputs these things:
from aspnet-api-versioning.
I am not sure what you are after here but in the last day or so I have been adding swagger and api versioning to a new core api site I am working on. I wanted my version and a functional area split out in my swagger docs. I am using swashbuckle to implement swagger (Swashbuckle.AspNetCore). The way I implemented this was all on the swagger generation side not in versioning. I decided to generate separate documents for each API version (and namespace in my case) I was going to have. Then it is just a mater of selecting the document for the api I want to see. You can also insert a default query or header parameter and it will just work. I have attached some of my code if it helps.
In the end I get a list of swagger documents for my api that is split by a functional area (portion of the namespace) and api version ie
DoSomeWorkGroup1 - v1.0
DoSomeWorkGroup1 - v2.0
DoSomeWorkGroup2 - v2.0
etc
Generate a list of Namespaces and Versions for Swagger:
public static class SwaggerDocuments
{
public static List<SwaggerDocument> GetSwaggerDocumentList()
{
var APIGroups = new List<SwaggerDocument>();
Assembly asm = Assembly.GetExecutingAssembly();
var controllers = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type => type.GetMethods())
.Where(method => method.IsPublic && !method.IsDefined(typeof(NonActionAttribute)));
foreach (var controller in controllers)
{
Type t = controller.GetType();
var Namespace = controller.DeclaringType.Namespace;
var attributes = controller.DeclaringType.CustomAttributes;
foreach (var item in attributes)
{
if (item.AttributeType == typeof(ApiVersionAttribute))
{
foreach (var version in item.ConstructorArguments)
{
APIGroups.Add(new SwaggerDocument() { Namespace = Namespace.Replace("<Namespace Prefix I want Removed>.", "").Split('.').First(), Version = version.Value.ToString() });
}
}
}
}
return APIGroups.GroupBy(x => new { x.Namespace, x.Version }).Select(x => new SwaggerDocument { Namespace = x.Key.Namespace, Version = x.Key.Version }).ToList();
}
public class SwaggerDocument
{
public string Namespace { get; set; }
public string Version { get; set; }
}
}
Swagger generation in ConfigureServices of Startup Class
services.AddMvc(c =>
c.Conventions.Add(new ApiExplorerGroupPerVersionConvention())
);
services.AddSwaggerGen(c =>
{
var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "BG.Connect.API.xml");
c.IncludeXmlComments(filePath);
foreach (var item in Apilist)
{
c.SwaggerDoc($"{item.Namespace}{item.Version}", new Info { Title = $"{item.Namespace} API", Version = item.Version });
}
c.OperationFilter<AddRequiredHeaderParameter>();
c.DocInclusionPredicate((docName, apiDesc) =>
{
var restrictedVersion = apiDesc.ActionAttributes()
.OfType<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var versions = apiDesc.ControllerAttributes()
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
if (restrictedVersion.Count() > 0)
{
return restrictedVersion.Any(v => $"{apiDesc.GroupName}{v.ToString()}" == docName);
}
else
{
return versions.Any(v => $"{apiDesc.GroupName}{v.ToString()}" == docName);
}
});
});
Swagger UI Settings in Configure of Startup Class
app.UseSwaggerUi(c =>
{
foreach (var item in Apilist)
{
c.SwaggerEndpoint($"/swagger/{item.Namespace}{item.Version}/swagger.json", $"{item.Namespace} API - v{item.Version}");
}
});
Helper Class Used to Get the Portion of the namespace I want to split the documents by.
public class ApiExplorerGroupPerVersionConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
var controllerNamespace = controller.ControllerType.Namespace; // e.g. "Controllers.V1"
var apiVersion = controllerNamespace.Replace("<Namespace Prefix I want Removed>", "").Split('.').First();
controller.ApiExplorer.GroupName = apiVersion;
}
}
Helper Function to add the needed query or header parameters to all Item:
public class AddRequiredHeaderParameter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
string Version = "";
var controllerActionDescriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var controllerAttributes = controllerActionDescriptor.ControllerTypeInfo.CustomAttributes;
foreach (var item in controllerAttributes)
{
if (item.AttributeType == typeof(ApiVersionAttribute))
{
foreach (var version in item.ConstructorArguments)
{
Version = version.Value.ToString();
}
}
}
var methodAttributes = controllerActionDescriptor.MethodInfo.CustomAttributes;
foreach (var item in methodAttributes)
{
if (item.AttributeType == typeof(MapToApiVersionAttribute))
{
foreach (var version in item.ConstructorArguments)
{
Version = version.Value.ToString();
}
}
}
}
var header = new NonBodyParameter
{
Name = "api-version",
In = "query",
Required = true,
Type = "string",
Default = Version
};
if (operation.Parameters == null)
{
operation.Parameters = new List<IParameter>();
}
operation.Parameters.Add(header);
}
}
Hope this helps.
from aspnet-api-versioning.
Do you mean like releasing a package related to API Versioning with a solution from here packaged into a single library with easy setup?
from aspnet-api-versioning.
Exactly. An interesting challenge is how to aggregate the controller versions for documentation. In the versioning libraries this happens by letting the routing infrastructure find all candidates for a route and then aggregating from there. In addition, the client knows the route their looking for. For documentation, all of the routes need to be collated and then aggregated. I know this is possible, but the implementation has yet to be hashed out.
Another aspect is making sure that the documentation is built using the right abstractions. A lot of the early variants that I'm seeing people build are based on attributes. This not actually what the API versioning libraries use. The libraries only care about IApiVersionProvider and IApiVersionNeutral. One of the ways these interfaces are realized just happen to be attributes.
It's important for the right abstractions are used so that the solution is generic and can be used for various API versioning scenarios. Regardless, there has been some great progress in a number of attempts to create a library and I'll certainly be reviewing the implementations I know about for input to the out-of-the-box solution.
Now that I've nearly burned down all of the other issues, I should have some time (soon) to dedicate to this feature. Thanks for your patience.
from aspnet-api-versioning.
So what help do you need?
Do you want a pull request that adds a separate project with SwashBuckle filters that I referenced?
RemoveVersionParameters : IOperationFilter
abstract SetVersionInPaths : IDocumentFilter
that requires to implement version replacement logic.
from aspnet-api-versioning.
Someone looking to help ... yeah! Coincidentally, I've finally burned down just about every other outstanding issue, so I can now give this topic the full attention it deserves. Admittedly, I haven't spent a bunch of hands-on time with Swagger and Swashbuckle, so I'll be looking for feedback there for sure. I'll be catching myself up as quickly as possible. Here's the 10,000ft overview:
Objective
Provide an aggregated API version meta-model that groups all services (e.g. controllers) by route and their associated API versions. This is the part that is difficult and provides the value proposition to service authors. The result should be something analogous to, if not an implementation of, an API Explorer that is API version aware. This will provide all the heavy lifting for service authors and can potentially live directly within the API versioning libraries. I'm up in the air as to whether a separate library should be required for these capabilities. Opinions are welcome.
Requirements
- Controllers must be collated by route (this is probably the most challenging part)
- API version information must be based on IApiVersionProvider and IApiVersionNeutral (not solely attributes)
- Once you can get down to the controller or action descriptors, this information can be collected using the built-in GetApiVersionModel extension methods
- API version information should be aggregated into a single ApiVersionModel per route
- Built-in extension methods exist to aggregate ApiVersionModel instances
- Implement IApiExplorer for ASP.NET Web API, if possible/feasible
- Implement IApiDescriptionProvider for ASP.NET Core, if possible/feasible
from aspnet-api-versioning.
ApiVersionModel usage is pretty low-level, so let me elaborate a little about how it's used. I'll limit the specifics to ASP.NET Core, but things work similarly in Web API. Ultimately, the logic should be very close to the way that the action selector works.
If API versioning is enabled, then you can grab the ApiVersionModel as you've shown; however, there's a chance that it's not and the model will be null
so you have to account for that. In addition, if the action is implicitly versioned, then you'll have to fallback to getting the API version information from the controller model. I thought I had an extension method for this, but I guess in ASP.NET Core I don't. I think it's worth adding, so I'll open an issue for that. The implementation should look almost the same as the IsImplicitlyMappedTo extension method.
Once you've retrieved a model, that should be all that's necessary based on the example I'm seeing. The only time any of the properties on the model are empty is when it's version-neutral. Since the both version-neutral and any version are matches, these conditions seem unnecessary.
The DeclaredApiVersions are probably not useful for documentation. This collection is used by the controller and action selectors to find the matching implementation. The ImplementedApiVersions is an aggregation of the SupportedApiVersions and DeprecatedApiVersions for a single service. For creating a simple list, ImplementedApiVersions is probably sufficient; however, I suspect there would be a desire to know and document which API versions are deprecated. The ApiVersion class intentionally does not track that information. In order to bucketize these two groups, you'll want to use the SupportedApiVersions and DeprecatedApiVersions instead (though probably not in this code snippet).
I hope that provides some additional context.
from aspnet-api-versioning.
To complete answer, i think that actually retrieving ApiVersionModel is dependant to have an ApplicationModel, ControllerModel or ActionModel.
To be able to configure SwaggerUi middleware we need to juste have a class that allow to retrieve all api version from multiple provider (Implicit, Attrbiute, whatever)
from aspnet-api-versioning.
Sort of. The ControllerModel and ActionModel contain the information used to discover and populate the version information from attributes. This information is merged with any version information defined by conventions. The final set of version information is aggregated into a single ApiVersionModel and is attached as a property to the corresponding model. The ApiVersionModel defines a constructor that accepts the models, but this is purely a convenience as a shortcut to populate the information from attributes. Beyond that, there is no use or coupling to the models. The models and ApiVersionModel can still be built-up independent of this behavior.
Unless I'm mistaken, this behavior doesn't add any additional dependency coupling that didn't already exist. If it does, then we should consider changing it now before the 1.1 milestone is officially released. These constructors were previously internal, but changed recently due an extensibility bug.
from aspnet-api-versioning.
A quick update. I have first set of changes out for review in PR #103 which introduces support for the IApiExplorer in Web API. I know a lot of you are waiting for the ASP.NET Core flavor, but I wanted to get - what I believe will be - the hard one out of the way. I'm expecting the ASP.NET Core version to come sometime during the next week.
As a sanity check, if there is formal support for an API explorer that groups and enumerates all the controllers and actions by API version, is there really any other support needed to light up Swagger and/or Swashbuckle? It seems to me that the main challenge is collating all the metadata about API-versioned services. After that, the integration to Swagger and Swashbuckle should be business as usual, no?
from aspnet-api-versioning.
Alright folks, an alpha version of the ASP.NET Core functionality is now in PR #103. You can see how it comes together in the new Swagger Sample in the working branch.
Free feel to share your thoughts on the PR.
from aspnet-api-versioning.
I'll be updating the wiki soon.
Yes, please. Because I have no idea which things are now unnecessary in my previous Swagger usage implementation
from aspnet-api-versioning.
The first round of documentation is up. See the API Documentation topic. The sample projects should also help point you in the right direction. Feel free to ask questions if anything is unclear.
from aspnet-api-versioning.
Looks cool! I will try it tomorrow
from aspnet-api-versioning.
You can simplify sample by moving provider
resolution to method parameter like this
public void Configure( ...loggerFactory, IApiVersionDescriptionProvider provider )
{
...
app.UseSwaggerUI(
options =>
{
// build a swagger endpoint for each discovered API version
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerEndpoint( $"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant() );
}
} );
}
from aspnet-api-versioning.
Reasonable. I'll update it.
from aspnet-api-versioning.
Related Issues (20)
- Raw Requested API Versions Causes Stack Overflow HOT 6
- Custom error handling in .NET6 HOT 13
- OpenAPI not working with version interleaving within single controller HOT 3
- ActionDescriptor no longer returns an ApiVersionModel property HOT 2
- ApiVersioningOptions UseApiBehavior removal HOT 3
- ASP.NET Web API versioning Migrate from QueryStringApiVersionReader to UrlSegmentApiVersionReader HOT 2
- only the 5.1.0 version of Microsoft.AspNetCore.Mvc.Versioning is deprecated HOT 3
- Problem with describing reponse codes in minimal api HOT 3
- Cannot run APIs with different controller names with same ControllerName attribute after migration HOT 6
- Different options in `ApiVersioningOptions.cs` between .NET Framework and .NET Core packages HOT 2
- WithOpenApi() ignore Api versioning readers HOT 4
- .net 8 support HOT 7
- Breaking changes when migrating to OData8 + new versioning HOT 10
- odata/$metadata returns 404 when all controllers are decorated with ApiVersionNeutralAttribute HOT 3
- AddVersionedApiExplorer not working in Asp.Versioning HOT 5
- VersionedApiDescriptionProvider does not set the correct SunsetPolicy to ApiDescription instances HOT 1
- Using ApiExplorerSettingsAttribute together with ApiVersionAttribute produces unexpected number of ApiVersionDescriptions HOT 5
- Asp.Net Core WebApi - AWS ECS Cluster Authentication failure HOT 2
- [Versioned Clients][API Notifications] Fails to read new versions when available HOT 2
- Swashbuckle documentation inconsistent with examples HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aspnet-api-versioning.