在以前的前台项目中,我们已经引入一套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路由的统一,同样的其他项目通过简单改写路由注入方法,也可以实现同样的效果。
扫码关注 了解更多