系列导航及源代码

需求

在日常开发中,我们需要给前端提供文档化的API接口定义,甚至需要模拟架设一个fake服务用来调试接口字段。或者对于后端开发人员来说,我们可以通过导入这个接口定义文件到Postman或者其他API客户端,省去我们手动录入的麻烦。所以本文就实现如何使用Swagger来管理API接口文档化。

但是在本文中,我们不涉及关于NSwag的相关内容,通过NSwag,我们甚至可以直接生成前端可以使用的接口定义。关于NSwag的使用方法,请参考:NSwag 和 ASP.NET Core 入门以及官方文档RicoSuter/NSwag

目标

实现TodoList项目的接口文档化。

原理与思路

在使用IDE或者cli生成新的Web API项目的时候,项目模版里已经自带了Swashbuckle.AspNetCore包用来生成swagger文档,我们需要使用这个包来实现相关功能。

实现

实现基础的Swagger API文档

Program中极有可能已经添加了SwaggerGen服务了,我们可以做一点小修改,因为之前我们写过两个版本的TodoItemController,希望将两个版本也反映到swagger文档中:

// 省略其他...
builder.Services.AddSwaggerGen(s =>
{
    s.SwaggerDoc("1.0", new OpenApiInfo { Title = "TodoList API", Version = "1.0"});
    s.SwaggerDoc("2.0", new OpenApiInfo { Title = "TodoList API", Version = "2.0"});
});

中间件的引入我们也可以修改一下:

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(s =>
    {
        s.SwaggerEndpoint("/swagger/1.0/swagger.json", "TodoList API v1.0");
        s.SwaggerEndpoint("/swagger/2.0/swagger.json", "TodoList API v2.0");
    });
}

如果在API接口版本控制的那一章我们不是使用的通过更改URL的方式实现的API多版本,那么现在只需要对应版本的Controller上添加:

  • TodoItemController.cs
[Route("/todo-item")]
[ApiExplorerSettings(GroupName = "1.0")]
[ApiController]
public class TodoItemController : ControllerBase
// 省略其他...

以及

  • TodoItemV2Controller.cs
[Route("/todo-item")]
[ApiExplorerSettings(GroupName = "2.0")]
[ApiController]
public class TodoItemV2Controller : ControllerBase
// 省略其他...

如果是使用URL路径实现不同版本API的文档,可以参考这篇文章的实现:ASP.NET Core 3.1 WebApi Swagger与API版本控制的美妙结合

为Swagger添加认证授权功能

为了添加授权支持,我们可以修改Swagger服务选项如下,增加授权配置:

  • Program.cs
// 省略其他
s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
    In = ParameterLocation.Header,
    Description = "Add JWT with Bearer",
    Name = "Authorization",
    Type = SecuritySchemeType.ApiKey,
    Scheme = "Bearer"
});

s.AddSecurityRequirement(new OpenApiSecurityRequirement
{
    {
        new OpenApiSecurityScheme
        {
            Reference = new OpenApiReference
            {
                Type = ReferenceType.SecurityScheme,
                Id = "Bearer"
            },
            Name = "Bearer",
        },
        new List<string>()
    }
});

此外因为我们需要验证Issuer和Audience信息,所以需要在Token中携带这些信息,这样Swagger才能授权成功,修改IdentityService发放Token中获取Claims的逻辑:

  • IdentityService.cs
private async Task<List<Claim>> GetClaims()
{
    // 演示了返回用户名和Role两个claims
    var claims = new List<Claim>
    {
        new(ClaimTypes.Name, User!.UserName),
        // 使用fallback去填充这两个字段,实际项目里可能不需要这样做
        new(JwtRegisteredClaimNames.Iss, _jwtConfiguration.ValidIssuer ?? "TodoListApi"),
        new(JwtRegisteredClaimNames.Aud, _jwtConfiguration.ValidAudience ?? "https://localhost:5050")
    };

    var roles = await _userManager.GetRolesAsync(User);
    claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

    return claims;
}

验证

启动Api项目,打开swagger地址,可以看到API版本选择,以及授权控制都在界面上有所显示。

具体的切换查看我就不贴截图了,大家可以自己试一试。

一点扩展

导入API客户端

右击swagger界面上的json文件链接选择另存为,再去对应的API客户端导入json文件即可。

Postman在这方面做的比较好的是它能够按照json文件内接口的结构关系生成对应的文件夹结构。

生成fake服务端

可以去这里:Swagger Editor,上传swagger json文件,选择生成服务端或者客户端。

为swagger生成完整的数据定义及API注释文档

需要开启XML注释功能,为此我们同时需要禁止1591warning(为了避免对所有的方法、类、字段发出没有xml注释文档的警告)。修改项目设置如下:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
  <DocumentationFile>TodoList.Api.xml</DocumentationFile>
  <OutputPath></OutputPath>
  <NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
  <NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>

修改SwaggerGen注入的配置:

  • TodoList.Api.csproj
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
s.IncludeXmlComments(xmlPath);

我们以CreateTodoList接口为例去添加xml注释,

  • TodoListController.cs
/// <summary>
/// 创建新的TodoList,只有Administrator角色的用户有此权限
/// </summary>
/// <param name="command">创建TodoList命令</param>
/// <returns></returns>
[HttpPost]
[Authorize(Policy = "OnlyAdmin")]
[ServiceFilter(typeof(LogFilterAttribute))]
public async Task<ApiResponse<Domain.Entities.TodoList>> Create([FromBody] CreateTodoListCommand command)
{
    return ApiResponse<Domain.Entities.TodoList>.Success(await _mediator. Send(command));
}

再打开swagger文档查看,可以看到swagger文档现在已经有接口说明了:

总结

在本文中我们实现了swagger文档的生成和一些配置选项的作用,如果需要用到更多OpenAPI相关的特性,推荐熟悉一下NSwag这个组件,它提供了更加强大的功能。

下一篇文章我们实现程序的健康检查功能。

参考资料

  1. NSwag 和 ASP.NET Core 入门
  2. RicoSuter/NSwag
  3. ASP.NET Core 3.1 WebApi Swagger与API版本控制的美妙结合