是否可以在 ASP .NET Core 中使用 Swashbuckle 在 Swagger 2.0 和 Open API 3 格式中公开相同的 Swagger JSON?
Is it possible to expose the same Swagger JSON in both Swagger 2.0 and Open API 3 formats with Swashbuckle in ASP .NET Core?
我们有一个仅适用于 Swagger 2.0 JSON 格式的遗留应用程序。对于其他所有内容,我们希望使用 Open API 格式。
Swashbuckle .NET Core 是否有任何方法可以在不同的 URL 下以不同的格式公开 JSON?看起来 UseSwagger
方法选项中的 SerializeAsV2
属性 对于所有端点都是全局的。
基本上,我希望以下端点包含不同格式的相同 API 数据。
/swagger/v1/openapi/swagger.json
/swagger/v1/swagger2/swagger.json
您可以将OpenAPI文档序列化为V2,自行服务。以SwaggerMiddleware
为参考:
第一次注册SwaggerGenerator
:
services.AddTransient<SwaggerGenerator>();
然后注入SwaggerGenerator
并构建文档。从端点或控制器提供服务。您可以将版本作为路径参数来决定服务哪个版本。
app.UseEndpoints(e =>
{
// ...
e.MapGet("/swagger/{documentName}/swagger.{version}.json", context =>
{
var documentName = context.Request.RouteValues.GetValueOrDefault("documentName", null) as string;
var version = context.Request.RouteValues.GetValueOrDefault("version", null) as string;
if (documentName is null || version is null)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
return Task.CompletedTask;
}
// inject SwaggerGenerator
var swaggerGenerator = context.RequestServices.GetRequiredService<SwaggerGenerator>();
var doc = swaggerGenerator.GetSwagger(documentName);
// serialize the document as json
using var writer = new StringWriter(CultureInfo.InvariantCulture);
var serializer = new OpenApiJsonWriter(writer);
if (version == "v2")
{
doc.SerializeAsV2(serializer);
}
else
{
doc.SerializeAsV3(serializer);
}
var json = writer.ToString();
// serve it as json
context.Response.ContentType = MediaTypeNames.Application.Json;
return context.Response.WriteAsync(json, new UTF8Encoding(false));
});
});
当您访问 /swagger/v1/openapi.v2.json
时,您将获得序列化为 v2 的 OpenAPI 文档。
{
"swagger": "2.0",
"info": {
"title": "ApiPlayground",
"version": "1.0"
},
"paths": { ... }
}
而 /swagger/v1/openapi.v3.json
将为您提供序列化为 v3 的文档:
{
"openapi": "3.0.1",
"info": {
"title": "ApiPlayground",
"version": "1.0"
},
"paths": { ... },
"components": { ... }
}
另一种方法是拆分请求管道:
// serve v3 from /swagger/v1/swagger.json
app.UseSwagger(o => o.RouteTemplate = "swagger/{documentName}/swagger.json");
// serve v2 from /swagger2/v1/swagger.json
app.Map("/swagger2", swaggerApp =>
swaggerApp.UseSwagger(options => {
// note the dropped prefix "swagger/"
options.RouteTemplate = "{documentName}/swagger.json";
options.SerializeAsV2 = true;
})
);
我们有一个仅适用于 Swagger 2.0 JSON 格式的遗留应用程序。对于其他所有内容,我们希望使用 Open API 格式。
Swashbuckle .NET Core 是否有任何方法可以在不同的 URL 下以不同的格式公开 JSON?看起来 UseSwagger
方法选项中的 SerializeAsV2
属性 对于所有端点都是全局的。
基本上,我希望以下端点包含不同格式的相同 API 数据。
/swagger/v1/openapi/swagger.json
/swagger/v1/swagger2/swagger.json
您可以将OpenAPI文档序列化为V2,自行服务。以SwaggerMiddleware
为参考:
第一次注册SwaggerGenerator
:
services.AddTransient<SwaggerGenerator>();
然后注入SwaggerGenerator
并构建文档。从端点或控制器提供服务。您可以将版本作为路径参数来决定服务哪个版本。
app.UseEndpoints(e =>
{
// ...
e.MapGet("/swagger/{documentName}/swagger.{version}.json", context =>
{
var documentName = context.Request.RouteValues.GetValueOrDefault("documentName", null) as string;
var version = context.Request.RouteValues.GetValueOrDefault("version", null) as string;
if (documentName is null || version is null)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
return Task.CompletedTask;
}
// inject SwaggerGenerator
var swaggerGenerator = context.RequestServices.GetRequiredService<SwaggerGenerator>();
var doc = swaggerGenerator.GetSwagger(documentName);
// serialize the document as json
using var writer = new StringWriter(CultureInfo.InvariantCulture);
var serializer = new OpenApiJsonWriter(writer);
if (version == "v2")
{
doc.SerializeAsV2(serializer);
}
else
{
doc.SerializeAsV3(serializer);
}
var json = writer.ToString();
// serve it as json
context.Response.ContentType = MediaTypeNames.Application.Json;
return context.Response.WriteAsync(json, new UTF8Encoding(false));
});
});
当您访问 /swagger/v1/openapi.v2.json
时,您将获得序列化为 v2 的 OpenAPI 文档。
{
"swagger": "2.0",
"info": {
"title": "ApiPlayground",
"version": "1.0"
},
"paths": { ... }
}
而 /swagger/v1/openapi.v3.json
将为您提供序列化为 v3 的文档:
{
"openapi": "3.0.1",
"info": {
"title": "ApiPlayground",
"version": "1.0"
},
"paths": { ... },
"components": { ... }
}
另一种方法是拆分请求管道:
// serve v3 from /swagger/v1/swagger.json
app.UseSwagger(o => o.RouteTemplate = "swagger/{documentName}/swagger.json");
// serve v2 from /swagger2/v1/swagger.json
app.Map("/swagger2", swaggerApp =>
swaggerApp.UseSwagger(options => {
// note the dropped prefix "swagger/"
options.RouteTemplate = "{documentName}/swagger.json";
options.SerializeAsV2 = true;
})
);