RESTful api 带有多个端点的 Swagger 文档中的版本控制和分组
RESTful api versioning and grouping in doc from Swagger with multiple endpoints
我正在尝试在具有 API 端点的 MVC dotnet Core 应用程序上实现版本选项。
我要的设置是这样的
--AiM api
|_v1
|_v2
--RMS api
|_v1
我大部分时间都在使用它,但是 v1 上的项目没有出现在 v2 上。输出是这样的
但是当我们到达 AiM v2
端点上的版本 2 时,我只有一项
这不是我所期待的
我做了一个测试,让每一个都像这样大摇大摆地显示在不同的页面上
在控制器中
[ApiVersion("2.0")]
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "aim_v1")]
[Route("aim/v{version:apiVersion}/write/")]
public class aimWriter_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Departments" })]
[HttpPost("departments/delete/{id}")]
public IActionResult departments(string foo)
{
return Json(new
{
results = "edited"
});
}
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/delete/{id}")]
public IActionResult contact_delete(string foo)
{
return Json(new
{
results = "edited"
});
}
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/activate/{id}")]
public IActionResult contact_activate(string foo)
{
return Json(new
{
results = "edited"
});
}
}
[ApiVersion("2.0")]
[ApiExplorerSettings(GroupName = "aim_v2")]
[Route("aim/v{version:apiVersion}/write/")]
public class aimWriter_v2Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/delete/{id}")]
public IActionResult contact_delete(string foo)
{
return Json(new
{
results = "edited"
});
}
}
[ApiVersion("2.0")]
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "aim_v1")]
[Route("aim/v{version:apiVersion}/")]
public class aim_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Rooms" })]
[HttpPost("rooms")]
public IActionResult rooms(string foo)
{
return Json(new
{
results = "foo"
});
}
[SwaggerOperation(Tags = new[] { "AiM Buildings" })]
[HttpPost("buildings/rooms/{id}")]
public IActionResult building_rooms(string foo)
{
return Json(new
{
results = "foo"
});
}
[SwaggerOperation(Tags = new[] { "AiM Rooms" })]
[HttpPost("rooms/{id}")]
public IActionResult room(string foo)
{
return Json(new
{
results = "foo"
});
}
}
// set up as just a new endpoint (NOTE: in different controller)
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "rms_v1")]
[Route("rms/v{version:apiVersion}/")]
public class rms_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "RMS Orders" })]
[HttpPost("set_order/{id}")]
public IActionResult set_order(string foo)
{
return Json(new
{
results = "foo"
});
}
}
而在Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting(options => options.LowercaseUrls = true);
services.AddMvc();
services.AddApiVersioning(options => {
options.AssumeDefaultVersionWhenUnspecified = true ;
options.DefaultApiVersion = new ApiVersion(new DateTime(2016, 7, 1));
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("aim_v1", new Info
{
Version = "aim/v1",
Title = "WSU HTTP API"
});
c.SwaggerDoc("aim_v2", new Info
{
Version = "aim/v2",
Title = "WSU HTTP API v2"
});
c.SwaggerDoc("rms_v1", new Info
{
Version = "rms/v1",
Title = "WSU HTTP API"
});
//Set the comments path for the swagger json and ui.
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var xmlPath = Path.Combine(basePath, "project.in.bin.def.xml");
c.IncludeXmlComments(xmlPath);
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(o =>
{
o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Host = httpReq.Host.Value);
o.RouteTemplate = "doc/{documentName}/scheme.json";
});
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "docs";
c.SwaggerEndpoint("/doc/aim_v1/scheme.json", "AiM v1.0.0");
c.SwaggerEndpoint("/doc/rms_v1/scheme.json", "Rms v1.0.0");
c.SwaggerEndpoint("/doc/aim_v2/scheme.json", "AiM v2.0.0");
});
}
并且在 index.html 中用于 swagger ui 文档模板文件有
<script type="text/javascript">
window.JSConfig = JSON.parse('{"SwaggerEndpoints":[{"Url":"/doc/aim_v1/scheme.json","Description":"AiM v1.0.0"},{"Url":"/doc/aim_v2/scheme.json","Description":"AiM v2.0.0"},{"Url":"/doc/rms_v1/scheme.json","Description":"RMS v1.0.0"}],"BooleanValues":["false","true"],"DocExpansion":"list","SupportedSubmitMethods":["get","post","put","delete","patch"],"OnCompleteScripts":[],"OnFailureScripts":[],"ShowRequestHeaders":false,"JsonEditor":false,"OAuth2ClientId":"your-client-id","OAuth2ClientSecret":"your-client-secret-if-required","OAuth2Realm":"your-realms","OAuth2AppName":"your-app-name","OAuth2ScopeSeparator":" ","OAuth2AdditionalQueryStringParams":{}}');
$(function () {
hljs.configure({
highlightSizeThreshold: 5000
});
// Pre load translate...
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: "/doc/aim_v1/scheme.json",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post'],
onComplete: function(swaggerApi, swaggerUi){
if(typeof initOAuth == "function") {
initOAuth({
clientId: "ffff==",
clientSecret: "bbbb",
realm: "wsu-api",
appName: "wsu-api-broker",
scopeSeparator: " ",
additionalQueryStringParams: {}
});
}
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
_.each(JSConfig.OnCompleteScripts, function (script) {
$.getScript(script);
});
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: false,
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
});
为了获得不同端点上的项目,我在 类 上使用了 [ApiExplorerSettings(GroupName = "aim_v1")]
并在 Startup.cs[=55= 中匹配了它们] 和 index.html 个文件。在这一点上,我不确定在哪里进行编辑以使所有 [ApiVersion("1.0")]
项目显示在 [ApiVersion("2.0")]
上,因为我认为 ApiExplorerSettings GroupName 就是它锁定的原因。
为了顺利集成一切,还需要添加官方API Explorer package for API Versioning. This will collate all of the API version information for you in a way that Swagger will understand. The official Swagger/Swashbuckle integration wiki topic有额外的细节和例子。
设置如下所示:
public void ConfigureServices( IServiceCollection services )
{
// note: this option is only necessary when versioning by url segment.
// the SubstitutionFormat property can be used to control the format of the API version
services.AddMvcCore().AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
} );
services.AddMvc();
services.AddApiVersioning();
services.AddSwaggerGen(
options =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerDoc( description.GroupName, CreateInfoForApiVersion( description ) );
}
options.IncludeXmlComments( XmlCommentsFilePath );
} );
}
public void Configure( IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider )
{
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerEndpoint( $"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant() );
}
} );
}
static string XmlCommentsFilePath
{
get
{
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var fileName = typeof( Startup ).GetTypeInfo().Assembly.GetName().Name + ".xml";
return Path.Combine( basePath, fileName );
}
}
static Info CreateInfoForApiVersion( ApiVersionDescription description )
{
var info = new Info()
{
Title = $"Sample API {description.ApiVersion}",
Version = description.ApiVersion.ToString(),
Description = "A sample application with Swagger, Swashbuckle, and API versioning.",
Contact = new Contact() { Name = "Bill Mei", Email = "bill.mei@somewhere.com" },
TermsOfService = "Shareware",
License = new License() { Name = "MIT", Url = "https://opensource.org/licenses/MIT" }
};
if ( description.IsDeprecated )
{
info.Description += " This API version has been deprecated.";
}
return info;
}
该问题有一个完整的有效答案:
正如作者所说,ConfigureServices 中的 AddSwaggerGen 中的 DocInclusionPredicate 正在执行将适当的控制器映射到所需的 swagger 文件的技巧。
我正在尝试在具有 API 端点的 MVC dotnet Core 应用程序上实现版本选项。
我要的设置是这样的
--AiM api
|_v1
|_v2
--RMS api
|_v1
我大部分时间都在使用它,但是 v1 上的项目没有出现在 v2 上。输出是这样的
但是当我们到达 AiM v2
端点上的版本 2 时,我只有一项
这不是我所期待的
我做了一个测试,让每一个都像这样大摇大摆地显示在不同的页面上
在控制器中
[ApiVersion("2.0")]
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "aim_v1")]
[Route("aim/v{version:apiVersion}/write/")]
public class aimWriter_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Departments" })]
[HttpPost("departments/delete/{id}")]
public IActionResult departments(string foo)
{
return Json(new
{
results = "edited"
});
}
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/delete/{id}")]
public IActionResult contact_delete(string foo)
{
return Json(new
{
results = "edited"
});
}
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/activate/{id}")]
public IActionResult contact_activate(string foo)
{
return Json(new
{
results = "edited"
});
}
}
[ApiVersion("2.0")]
[ApiExplorerSettings(GroupName = "aim_v2")]
[Route("aim/v{version:apiVersion}/write/")]
public class aimWriter_v2Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Contacts" })]
[HttpPost("contacts/delete/{id}")]
public IActionResult contact_delete(string foo)
{
return Json(new
{
results = "edited"
});
}
}
[ApiVersion("2.0")]
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "aim_v1")]
[Route("aim/v{version:apiVersion}/")]
public class aim_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "AiM Rooms" })]
[HttpPost("rooms")]
public IActionResult rooms(string foo)
{
return Json(new
{
results = "foo"
});
}
[SwaggerOperation(Tags = new[] { "AiM Buildings" })]
[HttpPost("buildings/rooms/{id}")]
public IActionResult building_rooms(string foo)
{
return Json(new
{
results = "foo"
});
}
[SwaggerOperation(Tags = new[] { "AiM Rooms" })]
[HttpPost("rooms/{id}")]
public IActionResult room(string foo)
{
return Json(new
{
results = "foo"
});
}
}
// set up as just a new endpoint (NOTE: in different controller)
[ApiVersion("1.0")]
[ApiExplorerSettings(GroupName = "rms_v1")]
[Route("rms/v{version:apiVersion}/")]
public class rms_v1Controller : Controller
{
[SwaggerOperation(Tags = new[] { "RMS Orders" })]
[HttpPost("set_order/{id}")]
public IActionResult set_order(string foo)
{
return Json(new
{
results = "foo"
});
}
}
而在Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting(options => options.LowercaseUrls = true);
services.AddMvc();
services.AddApiVersioning(options => {
options.AssumeDefaultVersionWhenUnspecified = true ;
options.DefaultApiVersion = new ApiVersion(new DateTime(2016, 7, 1));
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("aim_v1", new Info
{
Version = "aim/v1",
Title = "WSU HTTP API"
});
c.SwaggerDoc("aim_v2", new Info
{
Version = "aim/v2",
Title = "WSU HTTP API v2"
});
c.SwaggerDoc("rms_v1", new Info
{
Version = "rms/v1",
Title = "WSU HTTP API"
});
//Set the comments path for the swagger json and ui.
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var xmlPath = Path.Combine(basePath, "project.in.bin.def.xml");
c.IncludeXmlComments(xmlPath);
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(o =>
{
o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Host = httpReq.Host.Value);
o.RouteTemplate = "doc/{documentName}/scheme.json";
});
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "docs";
c.SwaggerEndpoint("/doc/aim_v1/scheme.json", "AiM v1.0.0");
c.SwaggerEndpoint("/doc/rms_v1/scheme.json", "Rms v1.0.0");
c.SwaggerEndpoint("/doc/aim_v2/scheme.json", "AiM v2.0.0");
});
}
并且在 index.html 中用于 swagger ui 文档模板文件有
<script type="text/javascript">
window.JSConfig = JSON.parse('{"SwaggerEndpoints":[{"Url":"/doc/aim_v1/scheme.json","Description":"AiM v1.0.0"},{"Url":"/doc/aim_v2/scheme.json","Description":"AiM v2.0.0"},{"Url":"/doc/rms_v1/scheme.json","Description":"RMS v1.0.0"}],"BooleanValues":["false","true"],"DocExpansion":"list","SupportedSubmitMethods":["get","post","put","delete","patch"],"OnCompleteScripts":[],"OnFailureScripts":[],"ShowRequestHeaders":false,"JsonEditor":false,"OAuth2ClientId":"your-client-id","OAuth2ClientSecret":"your-client-secret-if-required","OAuth2Realm":"your-realms","OAuth2AppName":"your-app-name","OAuth2ScopeSeparator":" ","OAuth2AdditionalQueryStringParams":{}}');
$(function () {
hljs.configure({
highlightSizeThreshold: 5000
});
// Pre load translate...
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: "/doc/aim_v1/scheme.json",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post'],
onComplete: function(swaggerApi, swaggerUi){
if(typeof initOAuth == "function") {
initOAuth({
clientId: "ffff==",
clientSecret: "bbbb",
realm: "wsu-api",
appName: "wsu-api-broker",
scopeSeparator: " ",
additionalQueryStringParams: {}
});
}
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
_.each(JSConfig.OnCompleteScripts, function (script) {
$.getScript(script);
});
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: false,
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
});
为了获得不同端点上的项目,我在 类 上使用了 [ApiExplorerSettings(GroupName = "aim_v1")]
并在 Startup.cs[=55= 中匹配了它们] 和 index.html 个文件。在这一点上,我不确定在哪里进行编辑以使所有 [ApiVersion("1.0")]
项目显示在 [ApiVersion("2.0")]
上,因为我认为 ApiExplorerSettings GroupName 就是它锁定的原因。
为了顺利集成一切,还需要添加官方API Explorer package for API Versioning. This will collate all of the API version information for you in a way that Swagger will understand. The official Swagger/Swashbuckle integration wiki topic有额外的细节和例子。
设置如下所示:
public void ConfigureServices( IServiceCollection services )
{
// note: this option is only necessary when versioning by url segment.
// the SubstitutionFormat property can be used to control the format of the API version
services.AddMvcCore().AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
} );
services.AddMvc();
services.AddApiVersioning();
services.AddSwaggerGen(
options =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerDoc( description.GroupName, CreateInfoForApiVersion( description ) );
}
options.IncludeXmlComments( XmlCommentsFilePath );
} );
}
public void Configure( IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider )
{
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerEndpoint( $"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant() );
}
} );
}
static string XmlCommentsFilePath
{
get
{
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var fileName = typeof( Startup ).GetTypeInfo().Assembly.GetName().Name + ".xml";
return Path.Combine( basePath, fileName );
}
}
static Info CreateInfoForApiVersion( ApiVersionDescription description )
{
var info = new Info()
{
Title = $"Sample API {description.ApiVersion}",
Version = description.ApiVersion.ToString(),
Description = "A sample application with Swagger, Swashbuckle, and API versioning.",
Contact = new Contact() { Name = "Bill Mei", Email = "bill.mei@somewhere.com" },
TermsOfService = "Shareware",
License = new License() { Name = "MIT", Url = "https://opensource.org/licenses/MIT" }
};
if ( description.IsDeprecated )
{
info.Description += " This API version has been deprecated.";
}
return info;
}
该问题有一个完整的有效答案:
正如作者所说,ConfigureServices 中的 AddSwaggerGen 中的 DocInclusionPredicate 正在执行将适当的控制器映射到所需的 swagger 文件的技巧。