微信扫码
添加专属顾问
我要投稿
将Swagger2.0升级至OpenAPI 3.0,解决参数映射与文档描述分离问题。 核心内容: 1. Swagger2.0在项目中引发的问题及隐患 2. 旧文档描述与参数映射的调整方案 3. 路由方案的调整与适配器设计思路
在以前的前台项目中,我们已经引入一套swagger2.0的语法准则,同时我们也定义了属于自己的一套返回数据结构。
但是swagger2.0的文档描述与参数映射赋值是分离开的,带来了两个问题:
以下面内容为例子,分开描述会带来两个隐患:
隐患1、参数在文档中缺少描述,如下:game_id在实际是需要传的参数且需要进行处理包括表单验证等。但下面文档显然没有描述。
隐患2、同样的就算文档描述了,参数实际处理也未必接收game_id,这种不明确的文档描述对项目维护与前期对接都是一种挑战。
参数接收与校验、传递都是通过独立key获取的,且每个项目与开发人员存在一定的操作差异
其实我们已经有了一套gf的参数赋值与验证规则,所以,本质上需要维持的是这套规则,兼容旧的路由注入方式。
如下:有了参数定义后,后续 文档描述生成、参数解析、参数验证、参数赋值 都依赖于参数定义,最后控制器拿到的也是根据参数定义设定的实际请求数据。
参数定义部分:
控制器处理部分:
同时因为有一个新项目开始开发,也开始在这套逻辑上探讨他的可行性。
为了更加了解当前做的调整,我们先看下旧的路由方案。
最主要的核心代码有两个
第一 路由注入:将结构体+方法名解析为路由检索所需的key,绑定key与当前执行方法关系,留于后续供请求时检索路由对应的执行方法
StructA.MethodA1 → [ "StructA::MethodA1" ] → func(StructA.MethodA1)
第二路由检索:将请求的path,切割后两位转化为结构体名+方法名,从而检索到对应对应的方法。
api/structA/methodA1 → [ "StructA::MethodA1" ] → func(StructA.MethodA1)
在维持路由检索不变的情况下(因为已经注入了一个全局路由处理的handel),我们能否再这个路由处理规则下转化为gf2的路由规范呢?
这里的想法是再外层增加一层适配器,他提供两个作用:
a、兼容原先路由解析处理方法,将 func (c *cXXX)XXX(ctx context.Context, req XXXXXReq) (XXXXXRes, error) 格式转化为 func (a *XXX) XXX(base *api_server_base.Base, arguments ...interface{}) error 方法格式
重点可以看 baseFunc 这里,解析到这个方法的格式符合 func (c *cXXX)XXX(ctx context.Context, req XXXXXReq) (XXXXXRes, error) 的格式,那么在这个方法的外围包装一层baseFunc方法,适应上面这里第二路由检索的统一处理封装。
b、预生成文档所需的结构内容
这里预生成了一个 goai.AddInput 结构体。完成了上面路由注入与处理兼容,我们只是让请求可以找到对应的处理方法,但是依然没有解决的问题是,文档生成要如何让gf通过读取指定的结构体。
这里先解释一下gf框架是怎么去将bind的Struct转化为对应的openapi的json的。我们先看当我们请求 127.0.0.1:8100/api.json 接口时发生了什么
第一步:路由器去找对应的openapiSpec方法,然后这个方法做的事情也很简单,将openapi变量去转化为json就结束了
那么对于我们的关注点来讲,是不是只要知道openapi这个变量是什么时候被填充数据,怎么被填充的就可以了
第二步:我们找到对应加入openapi的方法,幸运的是跟我们猜想的一样,这里也很简单,他会通过判断in的类型如果为func,就认为是通过func (c *cXXX)XXX(ctx context.Context, req XXXXXReq) (XXXXXRes, error)格式注入的路由,则后续会按这个格式解析到req跟res的结构体,从而补全请求入参与出参。那么我们要做的事情就简单很多了,我们只需要通过解析 func (c *cXXX)XXX(ctx context.Context, req XXXXXReq) (XXXXXRes, error) 转化为对应 AddInput就行了。这里抓包查看下 AddInput的格式就知道了。
其中
path是路由“/StructName/MethorName”;
prefix一般没有先不管;
Method:“POST/GET”;
Object:对应的func:func (c *cXXX)XXX(ctx context.Context, req XXXXXReq) (XXXXXRes, error)
显然,前面路由注入的方法里我们已经拿到了 func,反射解析出 req对应的结构体,再从结构体的g.Meta标签中取出path与Method就行
具体代码如下:
控制器逻辑
参数处理与文档描述
测试与本地服务启动开放api.json接口
文档效果
至此,我们就完成了gf2与旧版base路由的统一,同样的其他项目通过简单改写路由注入方法,也可以实现同样的效果。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-03-16
AI 驱动的数据分析:Data Agent
2025-03-16
自然语言秒变SQL语句?极速体验 OB Cloud Text2SQL!
2025-03-16
Text2SQL零代码实战!RAGFlow 实现自然语言转 SQL 的终极指南
2025-03-15
ChatBI≠NL2SQL:关于问数,聊聊我踩过的坑和一点感悟
2025-03-13
SQL 开发者们,终于有了自己的“Cursor”
2025-03-12
DeepSeek + Power BI,PQ 智能拆分地址
2025-03-12
澜舟智库:表格智能问答,体验化繁为简的神奇力量
2025-03-11
DeepSeek+Dify查询数据库
2024-06-20
2024-10-14
2025-02-04
2024-10-09
2024-06-14
2024-06-16
2024-06-14
2024-05-31
2024-07-24
2024-07-03
2025-03-11
2025-03-10
2025-03-10
2025-02-28
2025-02-25
2025-02-22
2025-02-22
2025-01-30