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

news2024/11/23 18:33:58

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支持的四个服务器都可以这么做,但方法的名称可能不一样,还需要自己在对应的包,和生成的文件中找。


关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Allegro如何通过报表的方式检查单板上是否有假器件操作指导

Allegro如何通过报表的方式检查单板上是否有假器件操作指导 在做PCB设计的时候,输出生产文件之前,必须保证PCB上不能存在假器件,如下图,是不被允许的 当PCB单板比较大,如何通过报表的方式检查是否存在假器件,具体操作如下 点击Tools点击Reports

你看,ChatGPT都知道优先使用BigDecimal

不是三婶儿偏执,非要吐槽。家人们,咱就是说,按照基操逻辑谁会把严格金额计算相关的数据使用double类型呢… “我以为吕布已经够勇猛了,这是谁的部下?” 前几天,一同事让帮忙写段代码。内容比较常规&#xf…

iTerm2 的配置与美化

前言 iTerm2是默认终端的替代品,也是目前Mac系统下最好用的终端工具,集颜值和效率于一身。 最近换了一台新的 MacBook Pro ,需要重装电脑上的常用软件。为了将 ITerm2 DIY为自己喜欢的样子,花了不少时间。为了方便下次再配置&…

python五子棋代码最简单的,python五子棋代码画棋盘

大家好,本文将围绕python五子棋代码输赢逻辑判断展开说明,如何用python制作五子棋游戏是一个很多人都想弄明白的事情,想搞清楚python五子棋代码最简单的需要先了解以下几个事情。 1、求解用python 编写五子棋怎样编写判断输赢的函数&#xff…

C++项目——高并发内存池(1)--介绍及定长内存池

1.什么是内存池 1.1 池化技术 将程序中需要经常使用的核心资源先申请出来,放在一个池内,由程序自己管理,这样可以提高资源的使用效率,也可以保证本程序占有的资源数量。 比如之前博文实现的线程池,就是预先的申请出…

CRM哪家好?这5个CRM管理系统很好用!

CRM哪家好?这5个CRM管理系统很好用! CRM(Customer Relationship Management)即客户关系管理,能够帮助提高客户的价值、满意度、赢利性和忠实度,缩减销售周期和销售成本、增加收入、寻找扩展业务所需的新的市场和渠道,…

浅谈c++引用

浅谈c 在这里开设 <<浅谈C>> 系列专题,针对C重点内容展开探讨与观察底层,同时也是一个面试专栏,所选知识大多为面试常见问题.前期较为基础,难度会逐渐上升哦~ 本专栏采用经典的哲学三段论编写:是什么|为什么|怎么做 力图精简,高效. 第一章: 浅谈C函数重载 传送门…

ansible剧本(playbook)

目录 一、playbooks 概述以及实例操作 1、playbooks 的组成 2、操作示例一&#xff1a; 2.1 编写yaml文件也就是playbook 2.2 修改配置文件并放入/opt/目录下 2.3 运行playbook 3、操作实例二&#xff1a;定义、引用变量 4、操作示例三&#xff1a;指定远程主机sudo切换…

音频格式、参数、开发相关总结

常见的语音格式介绍PCM&#xff1a;音频纯裸数据。WAV&#xff1a;微软在windows存储的一种纯裸数据格式。AIFF&#xff1a;苹果在Mac上存储的一种纯裸数据格式。MP3&#xff1a;为ISO/IEC国际标准&#xff0c;是现在最普及的一种数字音频编码和有损压缩格式&#xff0c;几乎所…

Android Spider XX兔 Wechat Cookie 校验 注册案例(二)

声明 此次案例只为学习交流使用&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;切勿用于其他非法用途&#xff1b; 文章目录声明前言一、资源推荐二、任务说明三、App抓包分析四、还原JS加密1、Date类2、MD5类3、组合调用还原 api_token 参数4、execjs模…

04- 图像卷积及图片的模糊和边缘检测 (OpenCV基础) (机器视觉)

知识重点 padding指的就是填充的0的圈数重构图片大小: img cv2.resize(img, dsize(300, 300))模糊操作: dst cv2.filter2D(img, -1, kernel) kernel np.ones((5, 5), np.float32)/ 25 dst cv2.filter2D(img, -1, kernel) # 卷积操作 模糊操作: 方盒滤波: dst cv2.b…

AD使用教程 图文并茂 AD2020四层板

文章目录设计流程图&#xff1a;资源下载&#xff1a;自定义快捷键&#xff1a;&#xff08;按照个人习惯&#xff09;默认快捷键&#xff1a;一、软件主页面1.主界面2.Panels面板3.系统设置3.自定义快捷键4.新建工程二、原理图库1.原理图库面板2.管脚属性三、原理图绘制绘制步…

C++011-C++循环+枚举

文章目录C011-C循环枚举枚举枚举思想枚举举例题目描述 统计因数题目描述 质数判定错误方法一&#xff1a;优化方法1&#xff1a; 用break实现优化优化方法2&#xff1a; sqrt(n)题目描述 水仙花数题目描述 7744问题实现方法1优化方法2题目描述 余数相同问题题目描述 特殊自然数…

《第一行代码》 第六章:数据库与存储方案

一&#xff0c;持久化技术简介 也就是数据存储在内存中&#xff0c;会丢失。需要存储在存储设备中。而持久化技术&#xff0c;就是提供了手段&#xff0c;让数据再试瞬时状态和持久状态之间转换。 安卓开发提供了三种数据的持久化技术&#xff1a; 二&#xff0c;文件存储 …

【HDFS】FsDatasetImpl#getReplicaVisibleLength

调用点 DataNode.getReplicaVisibleLength(ExtendedBlock) (org.apache.hadoop.hdfs.server.datanode) // ClientDataNodeProtocolBlockChecksumComputer in BlockChecksumHelper.BlockChecksumComputer(DataNode, ExtendedBlock, BlockChecksumOptions) (org.apache.hadoop.hd…

ros中时间的概念:ros::Time、ros::Duration、定时器ros::Timerros::Rate、ros::WallTime

1. ros时间格式说明 有时刻和持续时长(可以是负数)&#xff0c;分为秒和纳秒&#xff0c;换算关系&#xff1a;1sec1e9nsec。Time指的是某个时刻&#xff0c;而Duration指的是某个时段。 int32 sec int32 nsec 2. ros::Time::now() 记录当前时刻 3. ros::Duration 代表持续的…

Linux 输出重定向 “>”、“>>”、“freopen”

有时候&#xff0c;我们编码时会使用printf或fprintf去打印输出调试信息或者报错信息&#xff0c;但正常这样去打印&#xff0c;只会显示在终端&#xff0c;如果终端关闭了&#xff0c;或者系统宕机了等&#xff0c;这些输出信息就没有了&#xff0c;为了将这些重要的信息保存下…

java诊断与调优常用命令jmap、jstack、jstat使用实战

java应用运行过程中难免会出现问题&#xff0c;特别是在生产环境&#xff0c;发生异常或宕机情况&#xff0c;需要诊断与分析&#xff0c;定位原因&#xff0c;进行优化&#xff0c;避免下次再次出现问题。 虽然现在有很多可视化工具&#xff0c;使用起来比命令行更方便&#x…

开学季好用电容笔有哪些?好用实惠的电容笔推荐

随着科学技术的快速发展&#xff0c;ipad的影响力越来越大&#xff0c;而且ipad的用户也越来越多&#xff0c;如果要提高ipad的功能&#xff0c;让ipad更加有趣&#xff0c;那么就需要一款非常适合自己&#xff0c;并且非常实用的电容笔。那么&#xff0c;究竟该选择哪个品牌的…

SpringBoot整合分布式锁redisson

1、导入maven坐标<!-- 用redisson作为所有分布式锁&#xff0c;分布式对象等功能框架--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.5</version></dependency>2、red…