如何在模块化单体架构中为Swashbuckle Swagger按模块拆分定义?
实现模块化单体架构下Swagger按模块分组展示
完全可以实现你的需求,核心思路是为每个模块生成独立的Swagger文档,通过过滤器筛选对应模块的端点,最后在Swagger UI中提供模块选择器。以下是具体实现步骤:
1. 为每个模块注册独立的Swagger文档
在Swagger配置中,遍历所有模块,为每个模块创建专属Swagger文档:
builder.Services.AddSwaggerGen(options => { var modules = builder.Services.BuildServiceProvider().GetRequiredService<IEnumerable<Module>>(); foreach (var module in modules) { options.SwaggerDoc(module.RoutePrefix, new OpenApiInfo { Title = $"{module.Name} API", Version = "v1" }); } });
2. 实现文档过滤器,筛选模块专属端点
创建IDocumentFilter,根据当前Swagger文档的标识(模块RoutePrefix),仅保留对应模块的端点:
public class ModuleSwaggerDocumentFilter : IDocumentFilter { private readonly IEnumerable<Module> _modules; public ModuleSwaggerDocumentFilter(IEnumerable<Module> modules) { _modules = modules; } public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { var targetModuleRoute = swaggerDoc.Name; var pathsToRemove = new List<KeyValuePair<string, OpenApiPathItem>>(); foreach (var path in swaggerDoc.Paths) { var apiDesc = context.ApiDescriptions.FirstOrDefault(api => api.RelativePath == path.Key.TrimStart('/')); if (apiDesc?.ActionDescriptor is ControllerActionDescriptor controllerAction) { controllerAction.RouteValues.TryGetValue("module", out var moduleRoute); if (moduleRoute != targetModuleRoute) { pathsToRemove.Add(path); } } } foreach (var path in pathsToRemove) { swaggerDoc.Paths.Remove(path.Key); } } }
将过滤器注册到SwaggerGen中:
builder.Services.AddSwaggerGen(options => { // 保留之前的模块文档注册代码 options.DocumentFilter<ModuleSwaggerDocumentFilter>(); });
3. 配置Swagger UI,启用模块选择器
在中间件配置中,为每个模块添加Swagger端点,Swagger UI顶部会自动生成模块下拉选择框:
app.UseSwaggerUI(options => { var modules = app.Services.GetRequiredService<IEnumerable<Module>>(); foreach (var module in modules) { options.SwaggerEndpoint($"/swagger/{module.RoutePrefix}/swagger.json", module.Name); } options.DocumentTitle = "模块化单体API文档"; });
结合现有路由约定
你已通过ModuleRoutingConvention为每个Action添加了module路由值,该值会被上述文档过滤器用来匹配模块,确保每个Swagger文档仅展示对应模块的端点。
内容的提问来源于stack exchange,提问作者R.Haughton
相关产品推荐
相关产品推荐

