每一個程序員都有重構他人代碼的沖動,但是,每一個程序員都不會有寫接口文檔的沖動。
據我所知,在.net項目中,很多同行的中小型項目接口文檔都使用Swagger,最近幾個朋友一起討論,有沒有比較好用的類似Swagger接口文檔開源項目,其中有朋友反饋說api太多的情況下,使用Swagger文檔就是一個災難,因為接口太多,前端開發人員很難找到自己想要的接口,因為所有的接口和接口實體類都展示在一個頁面上。
說實話,我以前還真沒有關注過這個問題,這兩天我有個項目,接口也比較多,自己在測試接口的時候才發現確實存在這種情況。由於公司內部還有一套自己的接口文檔框架,使用體驗相對於Swagger更優,所以我就想Swagger怎么就不能像我們自己的框架那樣,將webapi分組呢。后來查了些資料,Swagger團隊早就為我想到了,結論就是Swagger也支持接口分組。
一般我們分組都是按照控制器來分組,一個webapi控制器也就是一個模塊,具體實現我們往下看:
接入Swagger
1.在NuGet包管理器中安裝Swashbuckle.AspNetCore
2.添加配置文件:swaggergroupconfigs.json,文件內容如下:
{ "swaggergroupconfigs": [ { "GroupName": "Web", "Title": "Web模塊", "Version": "V1.0" }, { "GroupName": "Order", "Title": "訂單模塊", "Version": "V1.0" }, { "GroupName": "System", "Title": "系統模塊", "Version": "V1.0" } ] }
3.加載分組配置文件(這里使用了環境變量):
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostBuilderContext, configurationBuilder) => { var env = hostBuilderContext.HostingEnvironment; //optional:如果是必要的配置文件,可選就要設定為false,當文件不存在就會引發FileNotFoundException。 //reloadOnChange :如果文件被更新,是否更新IConfiguration實例的值。 configurationBuilder.AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true); configurationBuilder.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); configurationBuilder.AddJsonFile($"hosting.json", optional: true, reloadOnChange: true); configurationBuilder.AddJsonFile($"hosting.{env.EnvironmentName}.json", optional: false, reloadOnChange: true).Build(); configurationBuilder.AddJsonFile($"swaggergroupconfigs.json", optional: true, reloadOnChange: true); configurationBuilder.AddJsonFile($"swaggergroupconfigs.{env.EnvironmentName}.json", optional: false, reloadOnChange: true).Build(); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }).UseSerilog(dispose: true); }
4.注入Swagger服務
public void ConfigureServices(IServiceCollection services) { services.AddControllers();//Swagger接口模塊分組配置 var swaggergroupconfigs = Configuration.GetSection("swaggergroupconfigs").Get<List<SwaggerGroupConfig>>(); services.AddSwaggerGen(swoption => { swoption.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo() { Version = "1.2.10", Title = "Api Document", Description = "Api Document" }); #region Swagger接口模塊分組配置 swaggergroupconfigs.ForEach(group => { swoption.SwaggerDoc(group.GroupName, new OpenApiInfo { Title = group.Title, Version = group.Version }); //分組顯示 }); #endregion var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//獲取應用程序所在目錄(絕對,不受工作目錄影響,建議采用此方法獲取路徑) var xmlPath = Path.Combine(basePath, "Research.Web.xml"); swoption.IncludeXmlComments(xmlPath, true); }); }
5.啟用SwaggerUi中間件服務
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); //自定義中間件 app.UseRequestMiddlewares(); //啟用中間件服務生成Swagger作為JSON終結點 app.UseSwagger(); //啟用中間件服務對swagger-ui,指定Swagger JSON終結點 var swaggerGroupCofigs = Configuration.GetSection("swaggergroupconfigs").Get<List<SwaggerGroupConfig>>(); app.UseSwaggerUI(suoption => { suoption.SwaggerEndpoint("/swagger/v1/swagger.json", "Api Document"); suoption.RoutePrefix = string.Empty; swaggerGroupCofigs.ForEach(group => { suoption.SwaggerEndpoint($"/swagger/{group.GroupName}/swagger.json", group.Title); //分組顯示 }); }); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
public class SwaggerGroupConfig { public string GroupName { get; set; } public string Title { get; set; } public string Version { get; set; } }
6.在控制器類上添加分組特性(注意:GroupName值等於分組配置文件中對應的字段值)
using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Research.Web.Common; namespace Research.Web.Controllers { [ApiExplorerSettings(GroupName = "Order")] [ApiController] [Route("Order")] public class OrderController : ControllerBase { [HttpGet("Details")] public JsonResult Details(int id) { var claims = HttpContext.User.Claims.ToList(); var list = new List<object>(); claims.ForEach(claim => { list.Add(new { key = claim.Type, value = (claim.Type.Equals("nbf") || claim.Type.Equals("exp")) ? claim.Value.UnixTimeToDateTime() : claim.Value }); }); return new JsonResult(list); } } }
6.運行,查看效果如下: