echo和swagger的结合使用(oapi-codegen使用)

echo和swagger的结合使用(oapi-codegen使用)

相关官网:

  1. echo官网
  2. swagger

这里介绍的重点是swagger和echo的整合使用,具体的框架的使用方法请看官方文档。

1. 初衷

swagger官网提供了文档转代码的操作,但转出来的代码可用性不是很高(起码我还得再次修改一下),

我需要的是 swagger 直接转代码的能力,并且这个代码我不需要过多的操作。

兜兜转转我找到了类似的几个项目:

  1. go-swagger-github

    生成了一大堆代码,但这些不是我想要的,我还得修改很多,不合适

  2. echo-swagger-github

    注释写swagger文档,然后自动生成swagger yaml或者json文档,就像Java的swagger那样。我不喜欢这个方式,用注释来生成代替Java注解的功能这个点子很好,但这和注释结合在一起,总感觉怪怪的。

他们支持的swagger2.0,我需要的是3.0,并且他们提供的功能我不需要。于是乎找到了它

oapi-codegen

还有,需要有一个前端来显示swagger-ui。让我们可以看到文档, 并且可以利用文档调用接口,如下图所示。

在这里插入图片描述

2. oapi-codegen介绍

我选择它的点如下:

  1. 可以将文档转为代码,并且我不需要做过多的修改。
  2. 支持echo,gin,chi,net/http 这四种方式的整合。
  3. 面向对象生成controller,并且可对参数和响应做校验。
  4. 会生成对应接口的 query对象,requestBody对象,responseBody对象。
  5. 生成客户端代码。

使用方式

可以按照官网上的来,但官网的文档好像好久都没有更新了,最好看他们的example代码

https://github.com/deepmap/oapi-codegen/tree/master/examples

  1. 安装

    go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest
    
  2. 写swagger文档

    可以直接写按照swagger的规范,下面的演示我都是按照这个例子来的,可以直接cv Expanded Petstore

  3. 执行命令生成go文件

在这里插入图片描述

命令的参数解释如下:

using-oapi-codegen

这里执行如下:

oapi-codegen.exe -package echo_test  -generate "types,client,server,spec,strict-server" -o .\gen.go .\main.yaml

参数说明:

-package: 指定包名(必须)

-generate:指定需要生成的内容

-o:指定生成的代码位置

main.yaml:这是swagger文档内容

  1. 实现接口方法

在这里插入图片描述

它已经帮我们抽象出了接口。自己写个结构体实现此接口就好了,这就像java中的controller已经被写好了。直接用就好了。

在这里插入图片描述

剩下的就是自己写业务逻辑代码了,它已经帮我们写好controller了,并且路径参数和query参数已经被提取出来了

  1. 创建echo,将生成的代码和echo的路由注册连接起来

在这里插入图片描述

对图中1,2,3说明如下:

  1. 创建代码。
  2. 创建我们实现serverInterce接口的结构体。
  3. 注册。

在生成代码的时候可以指定服务器,它默认支持的echo。它会生成对应服务器的路由注册代码

在这里插入图片描述

对图中1,2,3说明如下:

  1. 是对应的服务器对象。

  2. 它帮我们生成的controller接口,我们要将创建好的对象传递过来。

  3. 指定根路由。

  4. 将代码运行起来,用postman调用就可以了。

到此,它已经帮我们弄好了请求,响应对象的创建,controller的编写,录取注册。

回头再看

  1. 生成了swagger文档中定义的model

在这里插入图片描述

在这里插入图片描述

需要注意,文档中可为不是必须的字段model中是对应的,tag不是必须,model中tag的类型为 指针。

  1. 生成了controller接口

在这里插入图片描述

  1. 将请求query参数和path参数提取了出来

在这里插入图片描述

还有path中的id参数,直接变为了方法参数。

  1. 生成了请求体和响应体

在这里插入图片描述

参数名字为 方法名字+RequestBody

在这里插入图片描述

参数名字为 方法名字+http状态码+Response

  1. 生成了客户端代码

在这里插入图片描述

上面的比较复杂的,它还提供了一种很简单的如下
在这里插入图片描述

New开头+方法名+request就找到了

当然还有response

在这里插入图片描述

parse开头+方法名+response就能得到响应了。

  1. 对它支持的服务器有中间件(请求参数,响应校验,yaml文件校验)
    在这里插入图片描述

需要注意,每次编辑完 swagger文件之后,都需要重新跑一下上面的命令,最新的代码

例子展示

请求参数校验
  1. yaml文件

    petstore-expanded的swagger文档中的/pets的get方法的name参数增加如下内容:

在这里插入图片描述

这个参数最大值为20,最小值为12

  1. 重新生成一下代码

     oapi-codegen.exe -package echo_test  -generate "types,client,server,spec,strict-server" -o .\gen.go .\main.yaml
    
  2. 在echo中使用参数校验中间件

    package main
    
    import (
    	middleware2 "github.com/deepmap/oapi-codegen/pkg/middleware"
    	"github.com/labstack/echo/v4"
    	"github.com/labstack/echo/v4/middleware"
    	echo_test "github.com/lc/echo_test1"
    	"github.com/lc/echo_test1/app"
    	"net/http"
    )
    
    func main() {
    	e := echo.New()
    	server := app.EchoServer{}
    	echo_test.RegisterHandlersWithBaseURL(e,server,"/echo_test")
        // 这是oapi-codegen对我们swagger文档生成的对象
    	swagger, err := echo_test.GetSwagger()
    	if err != nil {
    		panic(err)
    	}
    	// 增加参数校验中间件
        // 需要将swagger对象传递过去,它会对swagger对象做解析,对请求参数做校验
    	e.Use(middleware2.OapiRequestValidator(swagger))
    	err = e.Start(":8090")
    	if err != nil {
    		panic(err)
    	}
    }
    
  3. 验证

在这里插入图片描述

  1. 还可以对参数校验做自定义操作

    func main() {
    	e := echo.New()
    	server := app.EchoServer{}
    	echo_test.RegisterHandlersWithBaseURL(e,server,"/echo_test")
    
    	swagger, err := echo_test.GetSwagger()
    	if err != nil {
    		panic(err)
    	}
    	// 增加参数校验
    	//e.Use(middleware2.OapiRequestValidator(swagger))
        // 自定义参数验证
    	options := middleware2.Options{
    		ErrorHandler: func(c echo.Context, err *echo.HTTPError) error {
    			// 打印错误消息
    			println(err.Error())
    			// 这只是演示作用,强行将它改为ok
    			return c.String(http.StatusOK, "bad request")
    		},
    	}
    	e.Use(middleware2.OapiRequestValidatorWithOptions(swagger,&options))
    	err = e.Start(":8090")
    	if err != nil {
    		panic(err)
    	}
    }
    

在这里插入图片描述

请求体和响应体

POST/pets接口的方法AddPet中代码改为如下

func (e EchoServer) AddPet(ctx echo.Context) error {
    // 它帮我们生成好的请求体,结构体的命格式为:方法名字+json+requestBody
	var addPet echo_test.AddPetJSONRequestBody
    // 自己绑定参数
	ctx.Bind(&addPet)
    
	// 生成的响应体,对应java中的vo对象已经生成好了。结构体的命格式为:方法+状态码+json+Response
	AddPet200JSONResponse := echo_test.Pet{
		Id:   1,
		Name: addPet.Name,
		Tag:  addPet.Tag,
	}
	return ctx.JSON(http.StatusOK,AddPet200JSONResponse)
}
客户端的request和response

这里我们还是对上面的方法写单元测试。

func TestEchoServer_AddPet(t *testing.T) {
	var (
		e = echo.New()
		mock_server_addr = "/echo_test/"
		tag1 = "tag1"
		rec = httptest.NewRecorder()
	)
	echo_test.RegisterHandlersWithBaseURL(e,EchoServer{},"/echo_test")

	body := echo_test.AddPetJSONRequestBody{
		Name: "name1",
		Tag:  &tag1,
	}
	// 方便的方法,直接可以帮我们创建好request对象,这要放在原来的话,我们得通过	httptest.NewRequest()来自己构建了
	request, _ := echo_test.NewAddPetRequest(mock_server_addr,body)
	e.ServeHTTP(rec,request)
	// 还生成了解析的方法,直接将原始的response传递过去就可以解析好对应的response对象了
	response, err := echo_test.ParseAddPetResponse(rec.Result())
	assert.Nil(t, err)
	assert.Equal(t, body.Name,response.JSON200.Name)
}

swagger-ui展示

现在需要将swagger文档展示出来(在线看文档),并且还可以通过swagger来直接调用接口

想要的结果是

在这里插入图片描述

输入一个地址,就可以看到swagger文档。

为了做这个我们需要

  1. swagger文档显示(将yaml文件或者json文件转换为html页面)
  2. 怎么和echo做结合

swagger文档显示

swagger提供了swagger-ui来做展示,swagger-ui-安装-github

需要注意,swagger提供了好几个版本,这些版本的表现形式,提供的功能都不一样,这些和我们本身没有关系,我们只是将swagger文档提供给它,如果不喜欢这个版本的swagger-ui,还可以自己选择一个喜欢的,替换。

这里我们采用的是直接嵌入到html里面的安装方式

在这里插入图片描述

如下:

在这里插入图片描述

在这里插入图片描述

怎么和echo结合

swagger ui页面能干什么事情,是由他们(框架)决定的,我们能做的就是将yaml或者json文件给它就行。

我们只需要给他一个路径,返回yaml文件或者json文件就行。

  1. 修改html文件,配置swagger文档请求路由

在这里插入图片描述

  1. 在echo中配置中间件,对两种特殊路由来返回不同的数据

    • 获取swagger.yaml文件
    • 或者swagger-ui html

    代码如下:

    func main() {
    	e := echo.New()
    	server := app.EchoServer{}
    	echo_test.RegisterHandlersWithBaseURL(e,server,"/echo_test")
    	e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
    				AllowOrigins: []string{"*"},
    			}))
    	swagger, err := echo_test.GetSwagger()
    	if err != nil {
    		panic(err)
    	}
    	json, err := swagger.MarshalJSON()
    	if err != nil {
    		panic(err)
    	}
    	println(string(json))
        // 这里用pre是因为下面使用了oapi-codegen的校验,必须在它前面弄。
    	e.Pre(func(next echo.HandlerFunc) echo.HandlerFunc {
    		return func(c echo.Context) error {
                // 返回swagger yaml文件
    			if c.Request().URL.Path == "/echo_test/swagger.yaml"{
    				return c.File("main.yaml")
    			}
                 // 返回swagger html页面
    			if c.Request().URL.Path == "/echo_test/swagger_docs"{
    				return c.File("test.html")
    			}
    			return next(c)
    		}
    	})
    	e.Use(middleware2.OapiRequestValidator(swagger))
    	err = e.Start(":8090")
    	if err != nil {
    		panic(err)
    	}
    }
    
小优化点
  1. 对swagger文档优化

    上面,直接返回了swagger文档,建议使用oapi-codegen生成的swagger对象

    可变量不要太多,代码都是基于swagger文档来生成的,swagger文档必须要和代码同步。如果直接返回原始的swagger文档,会有不同步的情况出现,就会造成ui页面看着是对的,但代码不对,不能第一时间发现。

    修改代码如下:

在这里插入图片描述

swagger对象可以转换为swagger的json格式,我们以它为准。

还得修改一下html中配置url,将之前的yaml改为json

  1. 对html优化

    上面我们是直接返回了html文件,将配置写死了,不灵活。这里建议将html直接写到代码中,将可配置的部分抽取出来,利用go的temple做参数渲染

到这,开发流程如下:

  1. 写好swagger yaml文件(启动本地项目看swagger文档是否正确)
  2. 利用oapi-codegen来生成对应的代码。
  3. 实现接口,做业务逻辑。
  4. 利用生成的request,response model来做操作。
  5. 写单元测试,利用生成好的request,response来请求响应。
  6. 转测,自己可以在swagger-ui中调用接口做验证。

还有,我这里用的echo,oapi-codegen支持的四个服务器都可以这么做,但方法的名称可能不一样,还需要自己在对应的包,和生成的文件中找。


关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值