-
Couldn't load subscription status.
- Fork 716
Unique Swagger Description per Version #899
-
Using the ApiExplorer package, we can customize the description of the OpenApi document. However, looking through the examples you have out there (which are very helpful by the way), I don't see a way to make that unique per version / group name. Is this something that is supported? If not, is there an easy way to add this? If adding myself, it would have to be done through dependency injection. That is the only requirement.
Beta Was this translation helpful? Give feedback.
All reactions
📣 Follow up.
Enough people have asked about this over the years, that I've taken a hard look at how this would be implemented. A new feature is coming in 6.2 that will accommodate this type of group name.
The new configuration will look like:
services.AddApiVersioning() .AddApiExplorer( options => { options.GroupNameFormat = "'v'VVV"; options.FormatGroupName = (groupName, apiVersion) => $"{groupName}-{apiVersion}"; });
Let's say your controller looked like:
[ApiVersion( 1.0 )] [ApiController] [ApiExplorerSettings( GroupName = "Example" )] [Route( "[controller]" )] public class ExampleController : ControllerBase { [HttpGet] public IActionResult
Replies: 2 comments 2 replies
-
There is a long thread about this in #516, which also includes some possible solutions.
The crux of the problem is two-fold:
- The OpenAPI UI only has support for a single level of grouping
- Groups are defined by
ApiDescription.GroupName, which is intrinsically single-level
Both of these limitations make it difficult to do anything different; specifically, a group per name per API version. The list effectively has to be flattened to make anything work. If you put in the effort to change the UI, it's not an insane amount of work to group the code the way you want. Most people don't want to put in that much work though.
Currently, the rules are:
ApiDescription.GroupNamebecomesApiVersion.ToStringusingApiExplorerOptions.GroupNameFormat- Unless
ApiExplorerSettingsAttribute.GroupNameis explicitly set; then it is honored as is
Enough people have asked about this, that I can see adding an enhancement that would enable a 3rd+ option. That would enable a flattened, two-part group name without having to roll a bunch of infrastructure yourself.
Hopefully that answers your question and gives you a direction to go. I've mentally filed away this idea, but if you'd like to queue up formal enhancement issue, I'll endorse it. 😄
Beta Was this translation helpful? Give feedback.
All reactions
-
📣 Follow up.
Enough people have asked about this over the years, that I've taken a hard look at how this would be implemented. A new feature is coming in 6.2 that will accommodate this type of group name.
The new configuration will look like:
services.AddApiVersioning() .AddApiExplorer( options => { options.GroupNameFormat = "'v'VVV"; options.FormatGroupName = (groupName, apiVersion) => $"{groupName}-{apiVersion}"; });
Let's say your controller looked like:
[ApiVersion( 1.0 )] [ApiController] [ApiExplorerSettings( GroupName = "Example" )] [Route( "[controller]" )] public class ExampleController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); }
The final group name will become Example-v1. If other APIs in 1.0 do not have a group name, they will appear as v1. The API version string will always be provided according to the value of GroupNameFormat. Essentially, you just have to specify how the two strings should be combined together.
I'm working on the PR now. 6.2 should be published in the next day or two.
Beta Was this translation helpful? Give feedback.
All reactions
-
It's awesome to see you being so responsive to these requests, but...I think we may be miscommunicating. I was simply looking to create a unique description per instance of OpenApiInfo that is created. I can see now by using the 'group / version' wording, you thought I meant version specifically.
Going back to the example that I linked in the original post: on line 40, that OpenApiInfo object is created, but the only unique information populated in that object is the apiVersion from the ApiVersionDescription object on line 43. The remainder of the method is spent building up the description property of that same OpenApiInfo object, but it is the same for every version. I'd like the ability to pass some unique information there, but not sure how/if it's possible.
Beta Was this translation helpful? Give feedback.
All reactions
-
I see. Well, you can do just about whatever you want there. The possibilities are more about what you can do with Swashbuckle than anything else. Adding documentation as the following signature:
SwaggerDoc( string, OpenApiInfo )
I chose to use a static method that takes an ApiVersionDescription, creates an OpenApiInfo, and returns the created instance. You can replace that with any method or behavior you like,
The only thing you'll probably want to keep the same is looping over provider.ApiVersionDescriptions. This will provide the collated set of all API versions in the application. The GroupName is the formatted API version by default. The value specified must match the ApiDescription,GroupName. That is ultimately how Swashbuckle decides which descriptions are included in which document. This approach also keeps you from having to hardcode an explicit set of API versions.
The OpenApiInfo contains the top-level information for each group (e.g. API version). If you have you own method of mapping that to other information, it's pretty easy to do. You could even create an injectable service that you could pass which is populated from configuration or some external source.
For example:
interface IOpenApiInfoGenerator { OpenApiInfo Generate( ApiVersion apiVersion ); }
Then Line 40 can be replaced with:
var info = generator.Generate( description.ApiVersion );
If you want to customize more, you could pass ApiVersionDescription instead.
Hopefully, that gives you a few ideas.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1