6. 规范化接口文档
📝 模块更新日志
-
新特性
- 规范化处理自动过滤
SSE请求、文件请求、图片请求 4.9.1.6 ⏱️2023.11.22 #I8IP6D - 规范化文档枚举支持
[EnumToNumber]特性配置生成前端枚举定义代码是字符串值还是整数值类型,默认为字符串值 4.8.8.35 ⏱️2023.07.06 #I7IZ7S -
Swagger分组信息可在任意配置文件中通过[openapi:分组名]进行配置 4.8.8.26 ⏱️2023.06.20 a70eed3 -
Swagger请求授权失败后自动退出授权状态 4.8.6.12 ⏱️2023.02.20 !717 -
Swagger启用登录后配置CheckUrl可获取本地存储的Authorization请求报文头 4.8.6.2 ⏱️2023.02.10 #I6E3LB -
Swagger支持复制路由地址功能 4.8.4.13 ⏱️2023.01.11 #I5VNJI
- 规范化处理自动过滤
-
问题修复
-
Swagger进行分组后Tags不能进行分组过滤问题 4.8.8.22 ⏱️2023.05.25 #I78A55 - 因
4.8.7.22版本导致动态WebAPI类型注释丢失问题 4.8.7.27 ⏱️2023.03.29 #I6QM23 -
Swagger UI不显示ControllerBase派生类注释 4.8.7.22 ⏱️2023.03.27 #I6QM23 - 启用规范化结果后导致
WebSocket连接断开时出现异常 4.8.7.20 ⏱️2023.03.23 #I6PI5E -
Swagger接口排序同时指定Tag和Order之后无效 4.8.7.2 ⏱️2023.03.01 #I6IQDI #I6IP66 - 规范化结果不带
mini-profiler版本启动登录UI后不能传递headers问题 4.8.6.11 ⏱️2023.02.20 #I6G8IR - 规范化结果不支持
OData协议控制器 4.8.5.5 ⏱️2023.02.01 !571 - 启用
Swagger登录功能之后不能触发响应拦截器 4.8.5.5 ⏱️2023.02.01 #I6C9A2 !702 !703
-
-
其他调整
6.1 什么是接口文档
在现在移动为王、多端互辅、前端百花齐放的开放时代,不再是一人包揽式开发,大家各司其职,后端工程师负责接口开发,前端负责接口联调,也就是互联网现在流行的前后端分离架构。
所以就需要由前后端工程师共同定义接口,编写接口文档,之后大家按照这个接口文档进行开发、维护及开放给第三方。
6.2 为什么要写接口文档
- 能够让前端开发与后台开发人员更好的配合,提高工作效率
- 项目迭代或者项目人员更迭时,方便后期人员查看和维护
- 方便测试人员进行接口测试
6.3 为什么需要规范化文档
由于每个公司后端人员技术参差不齐,技术文档能力也不例外,导致接 口定义及文档五花八门,不同项目或不同公司对接极其困难,而且体验糟糕。所以,无规矩不成方圆,为了开发人员间更好的配合,迫切需要整理出一套规范。
通常接口规范分为六个部分:
6.3.1 协议规范
为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS 协议。为了确保数据交互安全,建议使用 HTTPS 协议
6.3.2 接口路径规范
作为接口路径,为了方便清晰的区分来自不同的系统,可以采用不同系统/模块名作为接口路径前缀,如:支付模块:/pay/xxx,订单模块:/order/xxx
6.3.3 版本控制规范
为了便于后期接口的升级和维护,建议在接口路径中加入版本号,便于管理,实现接口多版本的可维护性。如:接口路径中添加类似"v1"、"v2"等版本号
6.3.4 接口命名规范
和 C# 命名规范一样,好的、统一的接口命名规范,不仅可以增强其 可读性,而且还会减少很多不必要的口头/书面上的解释。可使用"驼峰命名法"按照实现接口的业务类型、业务场景等命名,有必要时可采取多级目录命名,但目录不宜过长,两级目录较为适宜
常见命名方式:接口名称动词前/后缀化: 接口名称以接口数据操作的动词为前/后缀,常见动词有:Add、Delete、Update、Query、Get、Send、Save、Detail、List等,如:新建用户AddUser、查询订单详情QueryOrderDetail。接口名称动词 + 请求方式:接口路径中包含具体接口名称的名词,接口数据操作动作以 HTTP 请求方式来区分。常用的 HTTP 请求方式有:GET:从服务器取出资源(一项或多项)POST:在服务器新建一个资源PUT:在服务器更新资源(客户端提供改变后的完整资源)PATCH:在服务器更新资源(客户端提供改变的属性)DELETE:从服务器删除资源
6.3.5 请求参数规范
请求方式:按照GET、POST、PUT等含义定义,避免出现不一致现象,对人造成误解、歧义请求头:请求头根据项目需求添加配置参数。如:请求数据格式,accept=application/json等。如有需要,请求头可根据项目需求要求传入用户 token、唯一验签码等加密数据请求参数/请求体: 请求参数字段,尽可能与数据库表字段、 对象属性名等保持一致,因为保持一致是最省事,最舒服的一件事
6.3.6 返回数据规范
统一规范返回数据的格式,对己对彼都有好处,此处以 json 格式为例。返回数据应包含:返回状态码、返回状态信息、具体数据。返回数据中的状态码、状态信息,常指具体的业务状态,不建议和 HTTP 状态码混在一起。HTTP 状态,是用来体现 HTTP 链路状态情况,如:404-Not Found。HTTP 状态码和 json 结果中的状态码,并存尚可,用于体现不同维度的状态。
6.4 什么是 Swagger
相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。
其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。
发现了痛点就要去找解决方案。解决方案用的人多了,就成了标准的规范,这就是 Swagger 的由来。
通过这套规范,你只需要按照它的规 范去定义接口及接口相关的信息。再通过 Swagger 衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,生成多种语言的客户端和服务端的代码,以及在线接口调试页面等等。
这样,如果按照新的开发模式,在开发新版本或者迭代版本的时候,只需要更新 Swagger 描述文件,就可以自动生成接口文档和客户端服务端代码,做到调用端代码、服务端代码以及接口文档的一致性。
所以,Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful 风格的 Web 服务。
总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。
6.5 Swagger 使用
Furion 框架提供了非常方便且灵活的 Swagger 配置,无需增加额外学习成本。
6.5.1 注册服务
.AddInject[XXX]() 已经包含了 .AddSpecificationDocuments() 注册,无需再次注册。
.UseInject() 已经包含了 .UseSpecificationDocuments() 注册,无需再次注册。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Furion.Web.Core
{
[AppStartup(800)]
public sealed class FurWebCoreStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSpecificationDocuments();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other Codes
app.UseSpecificationDocuments();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
services.AddSpecificationDocuments() 通常和 .AddDynamicApiControllers() 成对出现。
6.5.2 默认地址
在 Furion 框架中,默认 规范化文档 地址为 /api 目录,支持自定义配置。
如下图所示:
可以通过两种方式配置:
app.UseInject("路由")方式,如
app.UseInject("testapi"); // 那么 /testapi 就是规范化地址
配置文件配置:
{
"SpecificationDocumentSettings": {
"RoutePrefix": "testapi"
}
}
配置文件优先级大于 UseInject() 方式
6.5.3 默认分组
Furion 框架中默认分组名为 Default,支持自定义配置。
{
"SpecificationDocumentSettings": {
"DefaultGroupName": "MyGroup"
}
}
6.5.4 文档注释
规范化文档默认扫描 Furion.Application,Furion.Web.Core,Furion.Web.Entry 三个程序集.xml 注释文件,支持自定义配置。
只支持 /// 标识的注释语法,如:类、方法、属性、参数、返回值、验证特性。
using Furion.DynamicApiController;
namespace Furion.Application
{
/// <summary>
/// 类注释
/// </summary>
public class FurionAppService : IDynamicApiController
{
/// <summary>
/// 方法注释
/// </summary>
/// <returns></returns>
public string Get()
{
return nameof(Furion);
}
/// <summary>
/// 带 ID 参数的方法注释
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public int Get(int id)
{
return id;
}
}
}
如下图所示:
如果文档注释没有显示,请检查项目 属性->生成->输出 中 XML 文档是否配置输出路径。注意:只有不带路径的 【项目名称.xml】 才会自动加载。
Debug 模式下和 Release 模式下的注释文件是不通用的,所以导致很多开发者发布到服务器上发现没有显示注释。我们只需要在 Visual Studio 中切换 Debug 模式为 Release,然后重新配置一次即可。
这样不管是 Debug 还是 Release 模式都会显示注释了。
6.5.5 多分组支持
多分组是一个系统中必备功能,我们可以将系统划分为多个模块,每个模块都独立的 api 配置。在 Furion 框架中,实现多分组非常简单。如:
using Furion.DynamicApiController;
namespace Furion.Application
{
[ApiDescriptionSettings("Group1")]
public class FurionAppService : IDynamicApiController
{
/// <summary>
/// 随父类 Group1 分组
/// </summary>
/// <returns></returns>
public string Post()
{
return nameof(Furion);
}
/// <summary>
/// 在 Group1、Group3 都有我
/// </summary>
/// <returns></returns>
[ApiDescriptionSettings("Group1", "Group3")]
public string Get()
{
return nameof(Furion);
}
/// <summary>
/// 我只在 Group2 出现
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[ApiDescriptionSettings("Group2")]
public int Get(int id)
{
return id;
}
}
}
如下图所示:
6.5.6 多分组排序
- 方式一
- 方式二
通过分组名称添加 @整数 进行排序
using Furion.DynamicApiController;
namespace Furion.Application
{
[ApiDescriptionSettings("Group1@1")]
public class FurionAppService : IDynamicApiController
{
public string Post()
{
return nameof(Furion);
}
[ApiDescriptionSettings("Group1", "Group3")]
public string Get()
{
return nameof(Furion);
}
[ApiDescriptionSettings("Group@2")]
public int Get(int id)
{
return id;
}
}
}
可以通过在分组名后面添加 @整数 进行排序,整数 越大排前面。如果分组名称多次指定且多次指定了 @整数 ,则自动取该分组最大的整数进行排序。
通过配置文件配置排序
{
"SpecificationDocumentSettings": {
"GroupOpenApiInfos": [
{
"Group": "Group1",
"Order": 1
},
{
"Group": "Group2",
"Order": 2
},
{
"Group": "Group3",
"Order": 0
}
]
}
}
如下图所示:
分组默认排序 Order 为 0。如果同时配置了 @整数 和 appsettings.json 配置文件,那么优先采用 appsettings.json 中的 Order