diff --git a/README.md b/README.md index 951d97d..1e3cc4f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ [![GoDoc](https://godoc.org/github.com/zc2638/swag?status.svg)](https://godoc.org/github.com/zc2638/swag) [![Go Report Card](https://goreportcard.com/badge/github.com/zc2638/swag)](https://goreportcard.com/report/github.com/zc2638/swag) -```swag``` is a lightweight library to generate swagger json for Go projects. +English | [简体中文](./README_zh.md) + +```swag``` is a lightweight library to generate swagger json for Golang projects. ```swag``` is heavily geared towards generating REST/JSON apis. @@ -39,8 +41,8 @@ However, it'll probably be useful if you include definitions of what ```GET /pet ```go allPets := endpoint.New("get", "/pet", "Return all the pets", - endpoint.Response(http.StatusOk, Pet{}, "Successful operation"), - endpoint.Response(http.StatusInternalServerError, Error{}, "Oops ... something went wrong"), +endpoint.Response(http.StatusOk, Pet{}, "Successful operation"), +endpoint.Response(http.StatusInternalServerError, Error{}, "Oops ... something went wrong"), ) ``` @@ -53,17 +55,17 @@ See the complete example below for how ```Walk``` can be used to bind endpoints ```go api := swag.New( - option.Title("Swagger Petstore"), - option.Endpoints(post, get), +option.Title("Swagger Petstore"), +option.Endpoints(post, get), ) // iterate over each endpoint, if we've defined a handler, we can use it to bind to the router. We're using ```gin`` // in this example, but any web framework will do. router := gin.New() api.Walk(func (path string, e *swag.Endpoint) { - h := e.Handler.(func (c *gin.Context)) - path = swag.ColonPath(path) - router.Handle(e.Method, path, h) +h := e.Handler.(func (c *gin.Context)) +path = swag.ColonPath(path) +router.Handle(e.Method, path, h) }) ``` @@ -71,17 +73,17 @@ api.Walk(func (path string, e *swag.Endpoint) { ```go func main() { - handle := swag.UIHandler("/swagger/ui", "", false) - patterns := swag.UIPatterns("/swagger/ui") - for _, pattern := range patterns { - http.DefaultServeMux.Handle(pattern, handle) - } +handle := swag.UIHandler("/swagger/ui", "", false) +patterns := swag.UIPatterns("/swagger/ui") +for _, pattern := range patterns { +http.DefaultServeMux.Handle(pattern, handle) +} - log.Fatal(http.ListenAndServe(":8080", nil)) +log.Fatal(http.ListenAndServe(":8080", nil)) } ``` -so you can visit for config: `http://localhost:8080/swagger/json` -so you can visit for ui: `http://localhost:8080/swagger/ui` + +so you can visit for UI: `http://localhost:8080/swagger/ui` ## Examples @@ -169,18 +171,18 @@ func main() { ```go func main() { - ... - // Note: Built-in routes cannot automatically resolve path parameters. - for p, endpoints := range api.Paths { - http.DefaultServeMux.Handle(path.Join(api.BasePath, p), endpoints) - } - http.DefaultServeMux.Handle("/swagger/json", api.Handler()) - patterns := swag.UIPatterns("/swagger/ui") - for _, pattern := range patterns { - http.DefaultServeMux.Handle(pattern, swag.UIHandler("/swagger/ui", "/swagger/json", true)) - } - - log.Fatal(http.ListenAndServe(":8080", nil)) +... +// Note: Built-in routes cannot automatically resolve path parameters. +for p, endpoints := range api.Paths { +http.DefaultServeMux.Handle(path.Join(api.BasePath, p), endpoints) +} +http.DefaultServeMux.Handle("/swagger/json", api.Handler()) +patterns := swag.UIPatterns("/swagger/ui") +for _, pattern := range patterns { +http.DefaultServeMux.Handle(pattern, swag.UIHandler("/swagger/ui", "/swagger/json", true)) +} + +log.Fatal(http.ListenAndServe(":8080", nil)) } ``` @@ -189,24 +191,24 @@ func main() { ```go func main() { - ... - - router := gin.New() - api.Walk(func (path string, e *swag.Endpoint) { - h := e.Handler.(http.Handler) - path = swag.ColonPath(path) - - router.Handle(e.Method, path, gin.WrapH(h)) - }) - - // Register Swagger JSON route - router.GET("/swagger/json", gin.WrapH(api.Handler())) - - // Register Swagger UI route - // To take effect, the swagger json route must be registered - router.GET("/swagger/ui/*any", gin.WrapH(swag.UIHandler("/swagger/ui", "/swagger/json", true))) - - log.Fatal(http.ListenAndServe(":8080", router)) +... + +router := gin.New() +api.Walk(func (path string, e *swag.Endpoint) { +h := e.Handler.(http.Handler) +path = swag.ColonPath(path) + +router.Handle(e.Method, path, gin.WrapH(h)) +}) + +// Register Swagger JSON route +router.GET("/swagger/json", gin.WrapH(api.Handler())) + +// Register Swagger UI route +// To take effect, the swagger json route must be registered +router.GET("/swagger/ui/*any", gin.WrapH(swag.UIHandler("/swagger/ui", "/swagger/json", true))) + +log.Fatal(http.ListenAndServe(":8080", router)) } ``` @@ -214,16 +216,16 @@ func main() { ```go func main() { - ... - - router := chi.NewRouter() - api.Walk(func (path string, e *swag.Endpoint) { - router.Method(e.Method, path, e.Handler.(http.Handler)) - }) - router.Handle("/swagger/json", api.Handler()) - router.Mount("/swagger/ui", swag.UIHandler("/swagger/ui", "/swagger/json", true)) - - log.Fatal(http.ListenAndServe(":8080", router)) +... + +router := chi.NewRouter() +api.Walk(func (path string, e *swag.Endpoint) { +router.Method(e.Method, path, e.Handler.(http.Handler)) +}) +router.Handle("/swagger/json", api.Handler()) +router.Mount("/swagger/ui", swag.UIHandler("/swagger/ui", "/swagger/json", true)) + +log.Fatal(http.ListenAndServe(":8080", router)) } ``` @@ -231,18 +233,18 @@ func main() { ```go func main() { - ... - - router := mux.NewRouter() - api.Walk(func (path string, e *swag.Endpoint) { - h := e.Handler.(http.HandlerFunc) - router.Path(path).Methods(e.Method).Handler(h) - }) - - router.Path("/swagger/json").Methods("GET").Handler(api.Handler()) - router.PathPrefix("/swagger/ui").Handler(swag.UIHandler("/swagger/ui", "/swagger/json", true)) - - log.Fatal(http.ListenAndServe(":8080", router)) +... + +router := mux.NewRouter() +api.Walk(func (path string, e *swag.Endpoint) { +h := e.Handler.(http.HandlerFunc) +router.Path(path).Methods(e.Method).Handler(h) +}) + +router.Path("/swagger/json").Methods("GET").Handler(api.Handler()) +router.PathPrefix("/swagger/ui").Handler(swag.UIHandler("/swagger/ui", "/swagger/json", true)) + +log.Fatal(http.ListenAndServe(":8080", router)) } ``` @@ -250,39 +252,39 @@ func main() { ```go func main() { - ... - - router := echo.New() - api.Walk(func (path string, e *swag.Endpoint) { - h := echo.WrapHandler(e.Handler.(http.Handler)) - path = swag.ColonPath(path) - - switch strings.ToLower(e.Method) { - case "get": - router.GET(path, h) - case "head": - router.HEAD(path, h) - case "options": - router.OPTIONS(path, h) - case "delete": - router.DELETE(path, h) - case "put": - router.PUT(path, h) - case "post": - router.POST(path, h) - case "trace": - router.TRACE(path, h) - case "patch": - router.PATCH(path, h) - case "connect": - router.CONNECT(path, h) - } - }) - - router.GET("/swagger/json", echo.WrapHandler(api.Handler())) - router.GET("/swagger/ui/*", echo.WrapHandler(swag.UIHandler("/swagger/ui", "/swagger/json", true))) - - log.Fatal(http.ListenAndServe(":8080", router)) +... + +router := echo.New() +api.Walk(func (path string, e *swag.Endpoint) { +h := echo.WrapHandler(e.Handler.(http.Handler)) +path = swag.ColonPath(path) + +switch strings.ToLower(e.Method) { +case "get": +router.GET(path, h) +case "head": +router.HEAD(path, h) +case "options": +router.OPTIONS(path, h) +case "delete": +router.DELETE(path, h) +case "put": +router.PUT(path, h) +case "post": +router.POST(path, h) +case "trace": +router.TRACE(path, h) +case "patch": +router.PATCH(path, h) +case "connect": +router.CONNECT(path, h) +} +}) + +router.GET("/swagger/json", echo.WrapHandler(api.Handler())) +router.GET("/swagger/ui/*", echo.WrapHandler(swag.UIHandler("/swagger/ui", "/swagger/json", true))) + +log.Fatal(http.ListenAndServe(":8080", router)) } ``` @@ -290,19 +292,19 @@ func main() { ```go func main() { - ... - - router := httprouter.New() - api.Walk(func (path string, e *swag.Endpoint) { - h := e.Handler.(http.Handler) - path = swag.ColonPath(path) - router.Handler(e.Method, path, h) - }) - - router.Handler(http.MethodGet, "/swagger/json", api.Handler()) - router.Handler(http.MethodGet, "/swagger/ui/*any", swag.UIHandler("/swagger/ui", "/swagger/json", true)) - - log.Fatal(http.ListenAndServe(":8080", router)) +... + +router := httprouter.New() +api.Walk(func (path string, e *swag.Endpoint) { +h := e.Handler.(http.Handler) +path = swag.ColonPath(path) +router.Handler(e.Method, path, h) +}) + +router.Handler(http.MethodGet, "/swagger/json", api.Handler()) +router.Handler(http.MethodGet, "/swagger/ui/*any", swag.UIHandler("/swagger/ui", "/swagger/json", true)) + +log.Fatal(http.ListenAndServe(":8080", router)) } ``` diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..1fa4e97 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,430 @@ +# swag + +![LICENSE](https://img.shields.io/github/license/zc2638/swag.svg?style=flat-square&color=blue) +[![GoDoc](https://godoc.org/github.com/zc2638/swag?status.svg)](https://godoc.org/github.com/zc2638/swag) +[![Go Report Card](https://goreportcard.com/badge/github.com/zc2638/swag)](https://goreportcard.com/report/github.com/zc2638/swag) + +[English](./README.md) | 简体中文 + +```swag``` 是一个轻量级的库,用于为 Golang 项目生成 `Swagger JSON`。 + +```swag``` 主要用于生成 REST/JSON API接口。 + +没有代码生成,没有框架约束,只是一个简单的 swagger 定义。 + +## 依赖 + +Golang 1.16+ + +## 安装 + +```shell +go get -u github.com/zc2638/swag +``` + +**Tip:** 从 `v1.2.0` 开始,低版本不再兼容。为了兼容大部分的web框架,整体架构做了很大的改动。 + +## 默认 Swagger UI 服务器 + +```go +func main() { + handle := swag.UIHandler("/swagger/ui", "", false) + patterns := swag.UIPatterns("/swagger/ui") + for _, pattern := range patterns { + http.DefaultServeMux.Handle(pattern, handle) + } + + log.Fatal(http.ListenAndServe(":8080", nil)) +} +``` +可以通过此地址访问 UI: `http://localhost:8080/swagger/ui` + +## Examples + +### 定义 + +```go +package main + +import ( + "fmt" + "io" + "net/http" + + "github.com/zc2638/swag" + "github.com/zc2638/swag/endpoint" + "github.com/zc2638/swag/option" +) + +// Category example from the swagger pet store +type Category struct { + ID int64 `json:"category"` + Name string `json:"name" enum:"dog,cat" required:""` + Exists *bool `json:"exists" required:""` +} + +// Pet example from the swagger pet store +type Pet struct { + ID int64 `json:"id"` + Category *Category `json:"category" desc:"分类"` + Name string `json:"name" required:"" example:"张三" desc:"名称"` + PhotoUrls []string `json:"photoUrls"` + Tags []string `json:"tags" desc:"标签"` +} + +func handle(w http.ResponseWriter, r *http.Request) { + _, _ = io.WriteString(w, fmt.Sprintf("[%s] Hello World!", r.Method)) +} + +func main() { + api := swag.New( + option.Title("Example API Doc"), + option.Security("petstore_auth", "read:pets"), + option.SecurityScheme("petstore_auth", + option.OAuth2Security("accessCode", "http://example.com/oauth/authorize", "http://example.com/oauth/token"), + option.OAuth2Scope("write:pets", "modify pets in your account"), + option.OAuth2Scope("read:pets", "read your pets"), + ), + ) + api.AddEndpoint( + endpoint.New( + http.MethodPost, "/pet", + endpoint.Handler(handle), + endpoint.Summary("Add a new pet to the store"), + endpoint.Description("Additional information on adding a pet to the store"), + endpoint.Body(Pet{}, "Pet object that needs to be added to the store", true), + endpoint.Response(http.StatusOK, "Successfully added pet", endpoint.Schema(Pet{})), + endpoint.Security("petstore_auth", "read:pets", "write:pets"), + ), + endpoint.New( + http.MethodGet, "/pet/{petId}", + endpoint.Handler(handle), + endpoint.Summary("Find pet by ID"), + endpoint.Path("petId", "integer", "ID of pet to return", true), + endpoint.Response(http.StatusOK, "successful operation", endpoint.Schema(Pet{})), + endpoint.Security("petstore_auth", "read:pets"), + ), + endpoint.New( + http.MethodPut, "/pet/{petId}", + endpoint.Handler(handle), + endpoint.Path("petId", "integer", "ID of pet to return", true), + endpoint.Security("petstore_auth", "read:pets"), + endpoint.ResponseSuccess(endpoint.Schema(struct { + ID string `json:"id"` + Name string `json:"name"` + }{})), + ), + ) + + ... +} + +``` + +### built-in + +```go +func main() { + ... + // Note: Built-in routes cannot automatically resolve path parameters. + for p, endpoints := range api.Paths { + http.DefaultServeMux.Handle(path.Join(api.BasePath, p), endpoints) + } + http.DefaultServeMux.Handle("/swagger/json", api.Handler()) + patterns := swag.UIPatterns("/swagger/ui") + for _, pattern := range patterns { + http.DefaultServeMux.Handle(pattern, swag.UIHandler("/swagger/ui", "/swagger/json", true)) + } + + log.Fatal(http.ListenAndServe(":8080", nil)) +} + +``` + +### gin + +```go +func main() { + ... + + router := gin.New() + api.Walk(func (path string, e *swag.Endpoint) { + h := e.Handler.(http.Handler) + path = swag.ColonPath(path) + + router.Handle(e.Method, path, gin.WrapH(h)) + }) + + // Register Swagger JSON route + router.GET("/swagger/json", gin.WrapH(api.Handler())) + + // Register Swagger UI route + // To take effect, the swagger json route must be registered + router.GET("/swagger/ui/*any", gin.WrapH(swag.UIHandler("/swagger/ui", "/swagger/json", true))) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### chi + +```go +func main() { + ... + + router := chi.NewRouter() + api.Walk(func (path string, e *swag.Endpoint) { + router.Method(e.Method, path, e.Handler.(http.Handler)) + }) + router.Handle("/swagger/json", api.Handler()) + router.Mount("/swagger/ui", swag.UIHandler("/swagger/ui", "/swagger/json", true)) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### mux + +```go +func main() { + ... + + router := mux.NewRouter() + api.Walk(func (path string, e *swag.Endpoint) { + h := e.Handler.(http.HandlerFunc) + router.Path(path).Methods(e.Method).Handler(h) + }) + + router.Path("/swagger/json").Methods("GET").Handler(api.Handler()) + router.PathPrefix("/swagger/ui").Handler(swag.UIHandler("/swagger/ui", "/swagger/json", true)) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### echo + +```go +func main() { + ... + + router := echo.New() + api.Walk(func (path string, e *swag.Endpoint) { + h := echo.WrapHandler(e.Handler.(http.Handler)) + path = swag.ColonPath(path) + + switch strings.ToLower(e.Method) { + case "get": + router.GET(path, h) + case "head": + router.HEAD(path, h) + case "options": + router.OPTIONS(path, h) + case "delete": + router.DELETE(path, h) + case "put": + router.PUT(path, h) + case "post": + router.POST(path, h) + case "trace": + router.TRACE(path, h) + case "patch": + router.PATCH(path, h) + case "connect": + router.CONNECT(path, h) + } + }) + + router.GET("/swagger/json", echo.WrapHandler(api.Handler())) + router.GET("/swagger/ui/*", echo.WrapHandler(swag.UIHandler("/swagger/ui", "/swagger/json", true))) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### httprouter + +```go +func main() { + ... + + router := httprouter.New() + api.Walk(func (path string, e *swag.Endpoint) { + h := e.Handler.(http.Handler) + path = swag.ColonPath(path) + router.Handler(e.Method, path, h) + }) + + router.Handler(http.MethodGet, "/swagger/json", api.Handler()) + router.Handler(http.MethodGet, "/swagger/ui/*any", swag.UIHandler("/swagger/ui", "/swagger/json", true)) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### fasthttp + +```go +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "path" + "path/filepath" + "strings" + + "github.com/fasthttp/router" + "github.com/valyala/fasthttp" + + "github.com/zc2638/swag" + "github.com/zc2638/swag/asserts" + "github.com/zc2638/swag/endpoint" + "github.com/zc2638/swag/option" +) + +// Category example from the swagger pet store +type Category struct { + ID int64 `json:"category"` + Name string `json:"name" enum:"dog,cat" required:""` + Exists *bool `json:"exists" required:""` +} + +// Pet example from the swagger pet store +type Pet struct { + ID int64 `json:"id"` + Category *Category `json:"category" desc:"分类"` + Name string `json:"name" required:"" example:"张三" desc:"名称"` + PhotoUrls []string `json:"photoUrls"` + Tags []string `json:"tags" desc:"标签"` +} + +func handle(ctx *fasthttp.RequestCtx) { + str := fmt.Sprintf("[%s] Hello World!", string(ctx.Method())) + _, _ = ctx.Write([]byte(str)) +} + +func main() { + post := endpoint.New("post", "/pet", endpoint.Summary("Add a new pet to the store"), + endpoint.Handler(handle), + endpoint.Description("Additional information on adding a pet to the store"), + endpoint.Body(Pet{}, "Pet object that needs to be added to the store", true), + endpoint.Response(http.StatusOK, "Successfully added pet", endpoint.Schema(Pet{})), + endpoint.Security("petstore_auth", "read:pets", "write:pets"), + ) + get := endpoint.New("get", "/pet/{petId}", endpoint.Summary("Find pet by ID"), + endpoint.Handler(handle), + endpoint.Path("petId", "integer", "ID of pet to return", true), + endpoint.Response(http.StatusOK, "successful operation", endpoint.Schema(Pet{})), + endpoint.Security("petstore_auth", "read:pets"), + ) + test := endpoint.New("put", "/pet/{petId}", + endpoint.Handler(handle), + endpoint.Path("petId", "integer", "ID of pet to return", true), + endpoint.Response(http.StatusOK, "successful operation", endpoint.Schema(struct { + ID string `json:"id"` + Name string `json:"name"` + }{})), + endpoint.Security("petstore_auth", "read:pets"), + ) + + api := swag.New( + option.Title("Example API Doc"), + option.Security("petstore_auth", "read:pets"), + option.SecurityScheme("petstore_auth", + option.OAuth2Security("accessCode", "http://example.com/oauth/authorize", "http://example.com/oauth/token"), + option.OAuth2Scope("write:pets", "modify pets in your account"), + option.OAuth2Scope("read:pets", "read your pets"), + ), + option.Endpoints(post, get), + ) + api.AddEndpoint(test) + + r := router.New() + api.Walk(func(path string, e *swag.Endpoint) { + if v, ok := e.Handler.(func(ctx *fasthttp.RequestCtx)); ok { + r.Handle(e.Method, path, fasthttp.RequestHandler(v)) + } else { + r.Handle(e.Method, path, e.Handler.(fasthttp.RequestHandler)) + } + }) + + buildSchemeFn := func(ctx *fasthttp.RequestCtx) string { + var scheme []byte + + if ctx.IsTLS() { + scheme = []byte("https") + } + if v := ctx.Request.Header.Peek("X-Forwarded-Proto"); v != nil { + scheme = v + } + if string(scheme) == "" { + scheme = ctx.URI().Scheme() + } + if string(scheme) == "" { + scheme = []byte("http") + } + return string(scheme) + } + + doc := api.Clone() + r.GET("/swagger/json", func(ctx *fasthttp.RequestCtx) { + scheme := buildSchemeFn(ctx) + doc.Host = string(ctx.Host()) + doc.Schemes = []string{scheme} + + b, err := json.Marshal(doc) + if err != nil { + ctx.Error("Parse API Doc exceptions", http.StatusInternalServerError) + return + } + _, _ = ctx.Write(b) + }) + + r.ANY("/swagger/ui/{any:*}", func(ctx *fasthttp.RequestCtx) { + currentPath := strings.TrimPrefix(string(ctx.Path()), "/swagger/ui") + + if currentPath == "/" || currentPath == "index.html" { + fullName := filepath.Join(asserts.DistDir, "index.html") + fileData, err := asserts.Dist.ReadFile(fullName) + if err != nil { + ctx.Error("index.html read exception", http.StatusInternalServerError) + return + } + + scheme := buildSchemeFn(ctx) + currentURI := scheme + "://" + path.Join(string(ctx.Host()), "/swagger/json") + + fileData = bytes.ReplaceAll(fileData, []byte(asserts.URL), []byte(currentURI)) + ctx.SetContentType("text/html; charset=utf-8") + ctx.Write(fileData) + return + } + sfs := swag.DirFS(asserts.DistDir, asserts.Dist) + file, err := sfs.Open(currentPath) + if err != nil { + ctx.Error(err.Error(), http.StatusInternalServerError) + return + } + + stat, err := file.Stat() + if err != nil { + ctx.Error(err.Error(), http.StatusInternalServerError) + return + } + + switch strings.TrimPrefix(filepath.Ext(stat.Name()), ".") { + case "css": + ctx.SetContentType("text/css; charset=utf-8") + case "js": + ctx.SetContentType("application/javascript") + } + io.Copy(ctx, file) + }) + + fasthttp.ListenAndServe(":8080", r.Handler) +} +``` diff --git a/go.mod b/go.mod index 94170bf..0a512b8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/zc2638/swag go 1.16 require ( - github.com/99nil/gopkg v0.0.0-20220531085926-60afce00972b + github.com/99nil/gopkg v0.0.0-20220607055250-e19b23d7661a github.com/modern-go/reflect2 v1.0.2 github.com/stretchr/testify v1.7.1 ) diff --git a/go.sum b/go.sum index 55e6cc7..4f89fd5 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/99nil/gopkg v0.0.0-20220531085926-60afce00972b h1:avQvIBcfzqSRWP5c6pYU7pqnGUXpurhX5u6Z1a+gym8= -github.com/99nil/gopkg v0.0.0-20220531085926-60afce00972b/go.mod h1:9qC2fDrE1huXJrcOPPeuaWNmkMoM7olCr+sD6qFs1eQ= +github.com/99nil/gopkg v0.0.0-20220607055250-e19b23d7661a h1:R2DqdZwoECFZIIxWL9DeyDLXoLgaJhus492ck5bH2to= +github.com/99nil/gopkg v0.0.0-20220607055250-e19b23d7661a/go.mod h1:Q/b1t+c95u1WpUKhSU/xsasqd2P+iZGS9eP7EDB7ZuU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -125,7 +125,6 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -240,9 +239,6 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -354,6 +350,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -467,7 +464,7 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -843,9 +840,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.3.4/go.mod h1:s4Tq0KmD0yhPGHbZEwg1VPlH0vT/GBHJZorPzhcxBUE= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=