<xmp id="63nn9"><video id="63nn9"></video></xmp>

<xmp id="63nn9"></xmp>

<wbr id="63nn9"><ins id="63nn9"></ins></wbr>

<wbr id="63nn9"></wbr><video id="63nn9"><ins id="63nn9"><table id="63nn9"></table></ins></video>

Loading

基于.NetCore開發博客項目 StarBlog - (26) 集成Swagger接口文檔

前言

這是StarBlog系列在2023年的第一篇更新??~

在之前的文章里,我們已經完成了部分接口的開發,接下來需要使用 curl、Postman 這類工具對這些接口進行測試,但接口一多,每次測試都要一個個填入地址和對應參數會比較麻煩…

我們需要一種直觀的方式來匯總項目里的所有接口,并且如果能直接在里面調試接口,那就更好了。

Swagger:誒嘿,說的不就是我嗎???

Swagger介紹

來一段官網的介紹

Simplify API development for users, teams, and enterprises with the Swagger open source and professional toolset.

翻譯:Swagger 是開源和專業的工具集,可以簡化用戶、團隊和企業的 API 開發。

一般來說,swagger用起來有兩部分,一個是 OpenAPI 一個是 SwaggerUI

在Swagger官網上,OpenAPI 介紹得天花亂墜??

The OpenAPI Specification, formerly known as the Swagger Specification, is the world’s standard for defining RESTful interfaces. The OAS enables developers to design a technology-agnostic API interface that forms the basis of their API development and consumption.

翻譯:OpenAPI 規范,以前稱為 Swagger 規范,是定義 RESTful 接口的世界標準。 OAS 使開發人員能夠設計一個與技術無關的 API 接口,該接口構成了他們 API 開發和使用的基礎。

簡單說 OpenAPI 是個標準,需要每種語言和框架自行實現一個工具,用來把項目里的接口都整合起來,生成 swagger.json 文件

然后 SwaggerUI 就是個網頁,讀取這個 swagger.json 就可以把所有接口以及參數顯示出來,還可以很方便調試,效果如圖。

image

Swashbuckle.AspNetCore

前面說到每種框架都要自己實現一個工具來生成 swagger.json ,這個 Swashbuckle.AspNetCore 就是 .NetCore 平臺的實現,用就完事了。

項目主頁: https://github.com/domaindrivendev/Swashbuckle.AspNetCore

Tips:如果是創建 WebApi 項目,代碼模板里面默認就有 Swagger 了,不用手動添加。

StarBlog項目一開始是使用MVC模板,所以沒有自帶Swagger,需要手動添加。

直接使用nuget添加 Swashbuckle.AspNetCore 這個包就完事了。

這個包功能很多,內置了 SwaggerUI 這個官方界面,還有一個 ReDoc 的純靜態接口文檔網頁(這個 ReDoc 只能看接口不能調試)。

初步使用

為了保證 Program.cs 代碼整潔,我們在 StarBlog.Web/Extensions 里面創建 ConfigureSwagger

public static class ConfigureSwagger {
  public static void AddSwagger(this IServiceCollection services) {
    services.AddSwaggerGen(options => {
      options.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "APIs"});

      // 在接口文檔上顯示 XML 注釋
      var filePath = Path.Combine(System.AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
      options.IncludeXmlComments(filePath, true);
    });
  }
  
  public static void UseSwaggerPkg(this IApplicationBuilder app) {
    app.UseSwagger();
    app.UseSwaggerUI(options => {
      options.RoutePrefix = "api-docs/swagger";
      options.SwaggerEndpoint("/swagger/v1/swagger.json", "APIs");
    });
    app.UseReDoc(options => {
      options.RoutePrefix = "api-docs/redoc";
      options.SpecUrl = "/swagger/v1/swagger.json";
    });
  }
}

上面代碼可以看到有三步

  • AddSwaggerGen - 對應前文說的生成 swagger.json
  • UseSwagger - 讓瀏覽器可以訪問到 /swagger/v1/swagger.json 這類路徑
  • UseSwaggerUI - 提供 SwaggerUI 的網頁訪問

然后回到 Program.cs 里面,分別注冊服務和添加中間件就好了。

// 注冊服務
builder.Services.AddSwagger();
// 添加中間件
app.UseSwaggerPkg();

現在啟動項目,訪問 http://[本地地址]/api-docs/swagger 就能看到接口文檔了

效果大概這樣

image

擴展:關于XML注釋

C# 的代碼注釋可以導出XML,然后顯示在 swagger 文檔上

注意需要手動在 .csproj 項目配置里面開啟,才會輸出XML文檔

<!--  輸出XML  -->
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

但是開啟XML之后,IDE很蠢的要求我們所有public成員都寫上注釋,很煩,加上 <NoWarn>$(NoWarn);1591</NoWarn> 這行就可以關掉這個警告。

在 Swagger 里加載XML文檔,既可以用本文前面寫的方式

var filePath = Path.Combine(System.AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
options.IncludeXmlComments(filePath, true);

還可以用第二種,加載目錄里的全部XML

var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
foreach (var file in xmlFiles) {
  options.IncludeXmlComments(file, true);
}

具體用哪種,都行吧,看心情~

擴展:關于 AddEndpointsApiExplorer

AddSwagger 擴展方法這里可能有同學會有疑問

為啥創建 .Net6 項目后默認是這兩行代碼

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

而我這里只有一行代碼

services.AddSwaggerGen();

先說結論:AddEndpointsApiExplorer 是為了支持 Minimal Api 的。

因為 StarBlog 項目使用的是MVC模板,在 Program.cs 的最開始可以看到這行代碼,添加控制器和視圖

builder.Services.AddControllersWithViews();

翻一下這個框架的源碼,可以看到這個方法的套娃是這樣的

AddControllersWithViews() -> AddControllersWithViewsCore() -> AddControllersCore()

而在 AddControllersCore 里面,又調用了 AddApiExplorer

private static IMvcCoreBuilder AddControllersCore(IServiceCollection services) {
  // This method excludes all of the view-related services by default.
  var builder = services
    .AddMvcCore()
    .AddApiExplorer()
    .AddAuthorization()
    .AddCors()
    .AddDataAnnotations()
    .AddFormatterMappings();

  if (MetadataUpdater.IsSupported) {
    services.TryAddEnumerable(
      ServiceDescriptor.Singleton<IActionDescriptorChangeProvider, HotReloadService>());
  }

  return builder;
}

就是說正常的項目已經有 ApiExplorer 這個東西了,但是 Minimal Api 項目沒有,所以本項目不需要 builder.Services.AddEndpointsApiExplorer(); 這行代碼。

詳情可以閱讀參考資料的第一個鏈接。

接口分組

接口文檔有了,但項目里接口太多了,幾十個接口全擠在一個頁面上,找都找得眼花了??

這時候可以給接口分個組

先來給 StarBlog 項目里面的接口分個類,根據不同用途,大致分成這五類:

  • admin - 管理員相關接口
  • common - 通用公共接口
  • auth - 授權接口
  • blog - 博客管理接口
  • test - 測試接口

還是在上面那個 ConfigureSwagger.cs 文件

修改 AddSwagger 方法,把這幾個分組添加進去

services.AddSwaggerGen(options => {
  options.SwaggerDoc("admin", new OpenApiInfo {
    Version = "v1",
    Title = "Admin APIs",
    Description = "管理員相關接口"
  });
  options.SwaggerDoc("common", new OpenApiInfo {
    Version = "v1",
    Title = "Common APIs",
    Description = "通用公共接口"
  });
  options.SwaggerDoc("auth", new OpenApiInfo {
    Version = "v1",
    Title = "Auth APIs",
    Description = "授權接口"
  });
  options.SwaggerDoc("blog", new OpenApiInfo {
    Version = "v1",
    Title = "Blog APIs",
    Description = "博客管理接口"
  });
  options.SwaggerDoc("test", new OpenApiInfo {
    Version = "v1",
    Title = "Test APIs",
    Description = "測試接口"
  });
});

這樣就會生成五個 swagger.json 文件,路徑分別是

  • /swagger/admin/swagger.json
  • /swagger/common/swagger.json
  • /swagger/auth/swagger.json
  • /swagger/blog/swagger.json
  • /swagger/test/swagger.json

所以下面的 UseSwaggerPkg 方法也要對應修改

public static void UseSwaggerPkg(this IApplicationBuilder app) {
  app.UseSwagger();
  app.UseSwaggerUI(options => {
    options.RoutePrefix = "api-docs/swagger";
    options.SwaggerEndpoint("/swagger/admin/swagger.json", "Admin");
    options.SwaggerEndpoint("/swagger/blog/swagger.json", "Blog");
    options.SwaggerEndpoint("/swagger/auth/swagger.json", "Auth");
    options.SwaggerEndpoint("/swagger/common/swagger.json", "Common");
    options.SwaggerEndpoint("/swagger/test/swagger.json", "Test");
  });
}

接下來,要讓 Swagger 知道每個接口都是屬于哪個分組的。

具體方法是在 Controller 上添加 ApiExplorerSettings 特性。

比如 BlogController 是屬于 blog 分組,在 class 定義前面添加一行代碼

[ApiExplorerSettings(GroupName = "blog")]
public class BlogController : ControllerBase {
  // ...
}

其他的 Controller 也是類似的操作,具體分組跟 StarBlog.Web/Apis 下的目錄結構一樣,這里就不贅述了。

實現效果

做完之后,打開 swagger 接口文檔頁面

可以看到右上角可以選擇接口分組了

image

搞定。

優化分組

前文對于 Swagger 分組的實現其實是一種硬編碼,不同分組的 Controller 上面需要加上 [ApiExplorerSettings(GroupName = "blog")] 特性,分組名全靠復制粘貼,在項目比較小的情況下還好,如果分組多起來了,有幾百個接口的時候,估計人就麻了吧??

Q:“你剛才干嘛不早說??”

A:“循序漸進嘛??”

A:“StarBlog項目也是最近才換到新版分組的??”

StarBlog.Web/Models 里添加個新的類 SwaggerGroup

public class SwaggerGroup {
    /// <summary>
    /// 組名稱(同時用于做URL前綴)
    /// </summary>
    public string Name { get; set; }

    public string? Title { get; set; }
    public string? Description { get; set; }

    public SwaggerGroup(string name, string? title = null, string? description = null) {
        Name = name;
        Title = title;
        Description = description;
    }

    /// <summary>
    /// 生成 <see cref="Microsoft.OpenApi.Models.OpenApiInfo"/>
    /// </summary>
    public OpenApiInfo ToOpenApiInfo(string version = "1.0") {
        var item = new OpenApiInfo();
        Title ??= Name;
        Description ??= Name;
        return new OpenApiInfo { Title = Title, Description = Description, Version = version };
    }
}

然后改造一下 StarBlog.Web/Extensions/ConfigureSwagger.cs

在這個文件里面添加個新的類,這樣就不會硬編碼了??

public static class ApiGroups {
  public const string Admin = "admin";
  public const string Auth = "auth";
  public const string Common = "common";
  public const string Blog = "blog";
  public const string Test = "test";
}

ConfigureSwagger 里添加一些代碼,創建 SwaggerGroup 列表

public static class ConfigureSwagger {
  public static readonly List<SwaggerGroup> Groups = new() {
    new SwaggerGroup(ApiGroups.Admin, "Admin APIs", "管理員相關接口"),
    new SwaggerGroup(ApiGroups.Auth, "Auth APIs", "授權接口"),
    new SwaggerGroup(ApiGroups.Common, "Common APIs", "通用公共接口"),
    new SwaggerGroup(ApiGroups.Blog, "Blog APIs", "博客管理接口"),
    new SwaggerGroup(ApiGroups.Test, "Test APIs", "測試接口")
  };
}

然后把后面的 AddSwagger 方法改成這樣,那一坨東西,現在一行代碼就代替了??

public static void AddSwagger(this IServiceCollection services) {
  services.AddSwaggerGen(options => {
    Groups.ForEach(group => options.SwaggerDoc(group.Name, group.ToOpenApiInfo()));

    // XML注釋
    var filePath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
    options.IncludeXmlComments(filePath, true);
  });
}

接著是 UseSwaggerPkg 方法,簡單??

public static void UseSwaggerPkg(this IApplicationBuilder app) {
  app.UseSwagger();
  app.UseSwaggerUI(opt => {
    opt.RoutePrefix = "api-docs/swagger";
    // 分組
    Groups.ForEach(group => opt.SwaggerEndpoint($"/swagger/{group.Name}/swagger.json", group.Name));
  });
}

Controller里面也對應修改成這樣

[ApiExplorerSettings(GroupName = ApiGroups.Blog)]
public class BlogController : ControllerBase {
}

完美????

小結

“Swagger之大,一鍋燉不下”

關于Swagger還有其他的用法,但需要一些前置知識,因此本文不會把StarBlog項目中關于Swagger的部分全部介紹完

等把相關的前置知識寫完,再來完善對應的用法~

這也跟StarBlog的開發過程是吻合的??

參考資料

系列文章

posted @ 2023-02-05 15:03  程序設計實驗室  閱讀(1187)  評論(0編輯  收藏  舉報
人碰人摸人爱免费视频播放

<xmp id="63nn9"><video id="63nn9"></video></xmp>

<xmp id="63nn9"></xmp>

<wbr id="63nn9"><ins id="63nn9"></ins></wbr>

<wbr id="63nn9"></wbr><video id="63nn9"><ins id="63nn9"><table id="63nn9"></table></ins></video>