Goui
Go-web如何一步步整合swagger-ui我们可以官方提供的方式:https://github.com/go-swagger/go-swagger , 主要方式是:1、写我们的go程序,2、让swagger工具扫描我们的go文件,3、生成swagger注释。
我们先说存在的问题:1、注释本地生成,会因为swagger版本不一致出现问题,出现各种git冲突,需要采用打包编译时去执行生成。2、违背了编程的方式。 3、为什么Java的swagger那么火,是因为和spring-boot完美整合,那么Spring解决的其实就是ioc的控制,所以go的web也不需要程序去控制,路由,输入,输出,所以我们需要这么做。 前期准备1、需要实现Spring-Boot的 controoler接口的方式
大致需求:1、拿到路由,2、拿到请求、响应(这个是go所有web框架做不到的,所以需要转变思想) @RestController public class UserController { @Autowired private UserRepository repository; @PostMapping("/save") public User echo(UserInfoDto info) { return repository.save(User.builder().id(info.getId()).userName(info.getName()).build()); } }2、转变思想
这个反射调用的框架,我写了一个,希望大家多多提交bug,因为反射本身缺陷很多:https://github.com/Anthony-Dong/gorpc var ( userService = service.NewUserService() ) func userRoute(e *engines.Engine) { g := e.Group("/report") g.POST("benchmark", http.NewHandlerFunc(userService.BenchMark)) } // 定义 context.Context(必不可少),类似于Java的ThreadLocal // request *dto.BenchmarkRequest 请求 // *dto.BenchmarkResponse 详情 // error 由于go本身没有throw,所以需要显示的申明 // 后期考虑加入web模块,但是目前主流web框架都是依赖于ctx向下传递,所以go和Java这点不一样(目前不考虑,可以考虑使用gin的context),虽然Springmvc中也可以接受http-request,http-response 但是由于它的bind,用户都不care了(这就是申明式编程的好处) type UserService interface { BenchMark(ctx context.Context, request *dto.BenchmarkRequest) (*dto.BenchmarkResponse, error) }
实现了这个,那么我们就开始吧,因为这些要求的,我们都可以拿到。 3、定义强路由
1、因为go本身并没有方法级别的注解,如果我们可以在每个interface上申明接口,在每个方法上申明路由 // path=/user_service type UserService interface { // path=/benchmark method=get BenchMark(ctx context.Context, request *dto.BenchmarkRequest) (*dto.BenchmarkResponse, cerror.Cerror) }
如果这样子,那么对于go的开发者特别不友好
2、所有采用func注册的方式
可以在接口后面指定get/其他 g.POST("benchmark", http.NewHandlerFunc(userService.BenchMark),op.Get())
目前采用的这种方式:1、可以显示的声明,符合go开发者的习惯,2、可以不用扫描go文件(spring-boot采用的这种方式) 整合swagger客户端找到swagger的web端资源包,然后将其都暴露出去,接下来核心就是 /swagger.json 了。
资源在我的这个项目的swagger里面 https://github.com/Anthony-Dong/gorpc ,后期会考虑静态资源使用api调用的方式(转发的方式),目前是借助工具写在了go文件里:https://github.com/a-urth/go-bindata ,这个工具很nice,可以讲文件写入到go文件里,以二进制的形式,我们知道go是不可以打包成jar包的,只有二进制文件,静态资源是一个很难受的事情,所以需要这么做。 const ( js = "js" css = "css" html = "html" byte = "byte" json = "json" ) func addSwagger(path string, _type string) func(writer http.ResponseWriter, request *http.Request) { return func(writer http.ResponseWriter, request *http.Request) { body, _ := swagger.Asset(path) switch _type { case js: writer.Header().Set("content-type", "application/javascript") case css: writer.Header().Set("content-type", "text/css") case json: writer.Header().Set("content-type", "application/json") } if _type == byte { fmt.Fprint(writer, body) return } fmt.Fprint(writer, string(body)) } } func addSwaggerRouter(path string, _type string) { http.HandleFunc("/"+path, addSwagger(path, _type)) } func main() { // swagger内置服务端需要的东西 addSwaggerRouter("swagger-ui/absolute-path.js", js) addSwaggerRouter("swagger-ui/favicon-16x16.png", byte) addSwaggerRouter("swagger-ui/favicon-32x32.png", byte) addSwaggerRouter("swagger-ui/index.html", html) addSwaggerRouter("swagger-ui/index.js", js) addSwaggerRouter("swagger-ui/oauth2-redirect.html", html) addSwaggerRouter("swagger-ui/package.json", json) addSwaggerRouter("swagger-ui/swagger-ui-bundle.js", js) addSwaggerRouter("swagger-ui/swagger-ui-bundle.js.map", html) addSwaggerRouter("swagger-ui/swagger-ui-standalone-preset.js", js) addSwaggerRouter("swagger-ui/swagger-ui-standalone-preset.js.map", html) addSwaggerRouter("swagger-ui/swagger-ui.css", css) addSwaggerRouter("swagger-ui/swagger-ui.css.map", html) addSwaggerRouter("swagger-ui/swagger-ui.js", js) addSwaggerRouter("swagger-ui/swagger-ui.js.map", html) http.HandleFunc("/swagger.json", func(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("content-type", "application/json") fmt.Fprintf(writer, doc) }) http.ListenAndServe(":8888", nil) }swagger-json
这个文件来自于 faygo,swagger核心是一个api接口,类似于下面这个样子 { "swagger": "2.0", "info": { "description": "Spring Swaager2 REST API", "version": "V1", "title": "REST API", "contact": { "name": "anthony", "url": "https://github.com/Anthony-Dong", "email": "574986060@qq.com" }, "license": { "name": "The Apache License", "url": "https://opensource.org/licenses/MIT" } }, "host": "localhost:8888", "basePath": "/", "tags": [ { "name": "user-controller", "description": "User Controller" } ], "paths": { "/find/{id}": { "get": { "tags": [ "user-controller" ], "summary": "find", "operationId": "findUsingGET", "produces": [ "*/*" ], "parameters": [ { "name": "id", "in": "path", "description": "id", "required": true, "type": "integer", "format": "int64" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/User" } } }, "deprecated": false } }, "/save/{name}": { "get": { "tags": [ "user-controller" ], "summary": "echo", "operationId": "echoUsingGET", "produces": [ "*/*" ], "parameters": [ { "name": "name", "in": "path", "description": "name", "required": true, "type": "string" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/User" } } }, "deprecated": false } } }, "definitions": { "User": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "userName": { "type": "string" } }, "title": "User" } } }一步步写doc
下面是swagger-doc的大致结构,我们必须将我们的api注入进去 doc := swagger.Swagger{ Version: swagger.Version, Info: &swagger.Info{ Title: "REST API", Contact: &swagger.Contact{ Email: "fanhaodong516@gmail.com", }, License: &swagger.License{ Name: "The Apache License", Url: "https://opensource.org/licenses/MIT", }, }, Host: "localhost:8888", BasePath: "/", Tags: []*swagger.Tag{}, //tag Paths: map[string]map[string]*swagger.Opera{},// 所有的api路由 Definitions: map[string]*swagger.Definition{},// 定义dto对象 }tag 是什么
user-controller 就是一个tag ,对于go来说一般是group可以定义为一个 controller
// Tag object Tag struct { Name string `json:"name"` // 一个标签:user-controller Description string `json:"description"` // 一个des:user-controller }
同时所有的 path 都可以指定多个tag Opera struct { Tags []string `json:"tags"` // 这里是tag Summary string `json:"summary"` Description string `json:"description"` OperationId string `json:"operationId"` Consumes []string `json:"consumes,omitempty"` Produces []string `json:"produces,omitempty"` Parameters []*Parameter `json:"parameters,omitempty"` Responses map[string]*Resp `json:"responses"` // {"httpcode":resp} Security []map[string][]string `json:"security,omitempty"` }认识path
这就是一个path Paths map[string]map[string]*Opera `json:"paths,omitempty"`
结构是个两级map "/save": { "post": { "tags": [ "user-controller" ], "summary": "echo", "operationId": "echoUsingPOST", "consumes": [ //请求类型 "application/json" ], "produces": [ // 响应类型 "*/*" ], "parameters": [ // 核心关注的点 ,如果多级别 { "name": "id", // 字段描述 "in": "query", // 查询 "required": false, // 是否强需求,可以借助于binding,也就是go的Validator(https://github.com/go-playground/validator) "type": "integer", // 类型 "format": "int64" // 真实类型(go类型) }, { "name": "name", "in": "query", "required": false, "type": "string" }, { "name": "user.id", "in": "query", "required": false, "type": "integer", "format": "int64" }, { "name": "user.userName", "in": "query", "required": false, "type": "string" } ], "responses": { "200": {// 状态吗 "description": "OK", // 响应描述 "schema": { "$ref": "#/definitions/User" // 指定路由:(nice,所以我们的dto全部放到modle里) } } }, "deprecated": false } },总结
通过以上,我们可以get到,确实是不是特别难,是有一定规律的,那么接下来,我们就可以开始设计框架了。
神雕后传郭芙生下三个儿子,孩子父亲是杨过,三个儿子威震江湖在神雕侠侣中,郭芙嫁给杨过被拒之后,兜兜转转嫁给了耶律齐,本以为嫁给了良人,实际上耶律齐最后却是害死黄药师段智兴和周伯通的凶手,说到这里,很多人不禁会问耶律齐这好好的上门女婿不做,
与其娇纵,不如给孩子来一顿毒打我们总想给孩子太多的爱,但真相是,我们以爱之名,给了他过多错误的呵护,把他养成了温室里苍白的花朵。首先,我不是狼爸,也痛恨用禁闭电疗等极端方法来给孩子断网瘾的张永信。但我总觉得,现
替父母收藏好这些饮食建议健康科普大赛我们的身体会随着年龄的变化不断地发生转变,尤其是到了50岁以后,身体的器官会有不同程度的衰退,尤其是消化和吸收能力的下降,会明显地影响老年人对食物的消化,摄取和吸收能力
穷不怪父,孝不比兄,苦不责妻,这才是人生的至高境界01穷不怪父。一个人出身低,乃至特别贫困,并不是上天不眷顾,反过来想,恰恰可能是上天给你的最好的锻炼机会。有很多人出身都很贫寒,最终却能通过自己的努力而一飞冲天,成功地实现自己人生
每天做这3件事,让自己变得越来越好来源新华社人生变得更灿烂和美好每个人都希望自己的人生会越变越好。坚持做这3件事,生活会越变越好。首先是靠近积极的人。每个人的身上,都有不同的能量和磁场。你选择和什么样的人在一起,就
今生,遇见你,是何其幸运?渺渺红尘,知己难寻人生若得一知己,足以慰风尘若得一位红颜知己,人生无憾?今生,遇见你,是何其幸运?昨天她说能做我的红颜知己。虽然我一直对她有无限的向往和遐想,但我却从不敢有什么真实
不知道选择第几代试管好?这些信息很关键,看完这篇文章就懂了对于想要做试管却不够了解试管的姐妹来说,最头疼的就是不知道自己最适合做哪一代试管,甚至以为做三代试管是最好的选择。首先说一下大家存在的误区很多姐妹都认为一代二代三代试管技术之间是升
马斯克恐吓裁员75本周一,推特员工写了一封公开信!抗议马斯克裁员计划。让我们看看硅谷打工人的勇气和反抗资本家的团结。起因是上周有媒体报道称,马斯克计划裁掉推特75的员工,员工数量将从7500人减少到
今天涨了!沪指收复3000点,逾4000股价上涨,A股牛市启动了吗?今天是2022年10月26日星期三,有料财经的股市行情分析和A股市场未来走势展望。作者财经有料哥有料财经今日股市表现与财经有料哥周二的股市分析推断结论一致,今天的股市行情让股民喜大
国机汽车前三季度净利润为2。47亿元,同比增30。9新京报贝壳财经讯10月26日,国机汽车发布第三季度报告,第三季度国机汽车实现营业收入为110。61亿元,同比增长29。09归属于上市公司股东的净利润为4666。4万元,同比下跌39
今年的天猫双11,似乎有点意思了今年的天猫双11,似乎有点意思了!不知不觉间双十一已经到了,10月24日晚八点天猫双十一也是开启了预售,让我没想到的是,现在的双十一和以前相比变化有点大,但是也更有意思了。不知道你