From 03d10208eceeef38957b677758c248f507c49b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Sat, 23 Aug 2025 10:51:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE=E5=9F=BA=E7=A1=80=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- define/openapi.go | 6 ++- enums/license.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++ geerate_option.go | 95 +++++++++++++++++++++++++++++++++++++ generate.go | 57 ++++++++++------------- swagger/parser.go | 1 + swagger/run.go | 8 ++-- 6 files changed, 245 insertions(+), 38 deletions(-) create mode 100644 enums/license.go create mode 100644 geerate_option.go diff --git a/define/openapi.go b/define/openapi.go index d238396..363f3b8 100644 --- a/define/openapi.go +++ b/define/openapi.go @@ -7,6 +7,8 @@ // Date : 2024-04-23 22:16 package define +import "git.zhangdeman.cn/gateway/api-doc/enums" + // OpenapiDoc openapi文档结构, 文档规范参见 : https://openapi.apifox.cn/ type OpenapiDoc struct { Openapi string `json:"openapi" required:"true"` // 必选. 这个字符串必须是开放 API 规范版本号提到的符合语义化版本号规范的版本号。openapi字段应该被工具或者客户端用来解释 OpenAPI 文档. @@ -231,8 +233,8 @@ type Contact struct { // License 开源协议 type License struct { - Name string `json:"name,omitempty"` // 开源协议名 - Url string `json:"url,omitempty"` // 开源协议地址 + Name enums.License `json:"name,omitempty"` // 开源协议名 + Url string `json:"url,omitempty"` // 开源协议地址 } // ServerItem server 对象结构 diff --git a/enums/license.go b/enums/license.go new file mode 100644 index 0000000..a91d994 --- /dev/null +++ b/enums/license.go @@ -0,0 +1,116 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 09:40 +package enums + +import ( + "strings" +) + +type License string + +func (l License) String() string { + return string(l) +} + +// MarshalJSON 支持序列化 +func (l License) MarshalJSON() ([]byte, error) { + return []byte(`"` + l.String() + `"`), nil +} + +// UnmarshalJSON 支持反序列化 +func (l *License) UnmarshalJSON(d []byte) error { + *l = License(strings.Trim(string(d), `"`)) + return nil +} + +const ( + LicenseAfl30 License = "AFL-3.0" + LicenseAgpl30 License = "AGPL-3.0" + LicenseApache10 License = "Apache-1.0" + LicenseApache11 License = "Apache-1.1" + LicenseApache20 License = "Apache-2.0" + LicenseArtistic20 License = "Artistic-2.0" + LicenseBsd2Clause License = "BSD-2-Clause" + LicenseBsd3Clause License = "BSD-3-Clause" + LicenseBsd4Clause License = "BSD-4-Clause" + LicenseBsl10 License = "BSL-1.0" + LicenseCcBy40 License = "CC-BY-4.0" + LicenseCcBySa40 License = "CC-BY-SA-4.0" + LicenseCc010 License = "CC0-1.0" + LicenseEcl20 License = "ECL-2.0" + LicenseEpl10 License = "EPL-1.0" + LicenseEpl20 License = "EPL-2.0" + LicenseEupl11 License = "EUPL-1.1" + LicenseEupl12 License = "EUPL-1.2" + LicenseGpl20 License = "GPL-2.0" + LicenseGpl30 License = "GPL-3.0" + LicenseIsc License = "ISC" + LicenseLgpl21 License = "LGPL-2.1" + LicenseLgpl30 License = "LGPL-3.0" + LicenseLppl13c License = "LPPL-1.3c" + LicenseMit License = "MIT" + LicenseMpl20 License = "MPL-2.0" + LicenseMsPl License = "MS-PL" + LicenseMsRl License = "MS-RL" + LicenseMulanpsl10 License = "MulanPSL-1.0" + LicenseMulanpubl10 License = "MulanPubL-1.0" + LicenseMulanpubl20 License = "MulanPubL-2.0" + LicenseNcsa License = "NCSA" + LicenseOfl11 License = "OFL-1.1" + LicenseOsl30 License = "OSL-3.0" + LicensePostgresql License = "PostgreSQL" + LicenseUpl10 License = "UPL-1.0" + LicenseUnlicense License = "Unlicense" + LicenseWtfpl License = "WTFPL" + LicenseZlib License = "Zlib" +) + +var ( + // LicenseUrlTable 洗衣链接表 + LicenseUrlTable = map[License]string{ + LicenseAfl30: "https://spdx.org/licenses/AFL-3.0", + LicenseAgpl30: "https://www.gnu.org/licenses/agpl-3.0.txt", + LicenseApache10: "https://www.apache.org/licenses/LICENSE-1.0", + LicenseApache11: "https://www.apache.org/licenses/LICENSE-1.1", + LicenseApache20: "https://www.apache.org/licenses/LICENSE-2.0.txt", + LicenseArtistic20: "https://spdx.org/licenses/Artistic-2.0", + LicenseBsd2Clause: "https://opensource.org/license/BSD-2-Clause", + LicenseBsd3Clause: "https://opensource.org/license/BSD-3-Clause", + LicenseBsd4Clause: "https://directory.fsf.org/wiki/License:BSD-4-Clause", + LicenseBsl10: "https://www.boost.org/LICENSE_1_0.txt", + LicenseCcBy40: "https://creativecommons.org/licenses/by/4.0/legalcode.txt", + LicenseCcBySa40: "https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt", + LicenseCc010: "https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt", + LicenseEcl20: "https://opensource.org/license/ecl-2-0", + LicenseEpl10: "https://www.eclipse.org/org/documents/epl-1.0/EPL-1.0.txt", + LicenseEpl20: "https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt", + LicenseEupl11: "https://joinup.ec.europa.eu/sites/default/files/custom-page/attachment/eupl1.1.-licence-en_0.pdf", + LicenseEupl12: "https://joinup.ec.europa.eu/sites/default/files/custom-page/attachment/eupl_v1.2_en.pdf", + LicenseGpl20: "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC1", + LicenseGpl30: "https://www.gnu.org/licenses/gpl-3.0.html#license-text", + LicenseIsc: "https://spdx.org/licenses/ISC", + LicenseLgpl21: "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html", + LicenseLgpl30: "https://www.gnu.org/licenses/lgpl-3.0-standalone.html", + LicenseLppl13c: "https://www.latex-project.org/lppl/lppl-1-3c.txt", + LicenseMit: "https://spdx.org/licenses/MIT", + LicenseMpl20: "https://www.mozilla.org/en-US/MPL/2.0/", + LicenseMsPl: "https://opensource.org/license/ms-pl-html", + LicenseMsRl: "https://opensource.org/license/ms-rl-html", + LicenseMulanpsl10: "http://license.coscl.org.cn/MulanPSL", + LicenseMulanpubl10: "http://license.coscl.org.cn/MulanPubL-1.0", + LicenseMulanpubl20: "http://license.coscl.org.cn/MulanPubL-2.0", + LicenseNcsa: "https://spdx.org/licenses/NCSA", + LicenseOfl11: "https://openfontlicense.org/documents/OFL.txt", + LicenseOsl30: "https://opensource.org/license/osl-3-0-php", + LicensePostgresql: "https://www.postgresql.org/about/licence/", + LicenseUpl10: "https://spdx.org/licenses/UPL-1.0", + LicenseUnlicense: "https://unlicense.org/", + LicenseWtfpl: "https://spdx.org/licenses/WTFPL", + LicenseZlib: "https://www.zlib.net/zlib_license.html", + } +) diff --git a/geerate_option.go b/geerate_option.go new file mode 100644 index 0000000..d40fbe2 --- /dev/null +++ b/geerate_option.go @@ -0,0 +1,95 @@ +// Package api_doc ... +// +// Description : api_doc ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 09:30 +package api_doc + +import ( + "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/gateway/api-doc/enums" +) + +// SetGenerateOption 设置文档生成选项 +type SetGenerateOption func(opt *define.OpenapiDoc) + +// generateOption 生成文档的一些配置选项 +type generateOption struct { + license enums.License // 文档的license + description string // 文档的描述 + title string // 文档的标题 +} + +// WithDocLicense 设置文档协议名称 + 协议链接 +func WithDocLicense(l enums.License) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + if l == "" { + return + } + opt.Info.License.Name = l + opt.Info.License.Url = enums.LicenseUrlTable[l] + } +} + +// WithDocDescription 设置文档描述 +func WithDocDescription(desc string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + if desc == "" { + return + } + opt.Info.Description = desc + } +} + +// WithDocTitle 设置文档标题 +func WithDocTitle(title string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + if len(title) == 0 { + return + } + opt.Info.Title = title + } +} + +// WithDocVersion 设置文档版本 +func WithDocVersion(version string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + opt.Info.Version = version + } +} + +// WithDocContactName 设置文档联系人名称 +func WithDocContactName(name string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + if name == "" { + return + } + opt.Info.Contact.Name = name + } +} + +// WithDocContactEmail 设置文档联系人邮箱 +func WithDocContactEmail(email string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + opt.Info.Contact.Email = email + } +} + +// WithDocContactHomePage 设置文档联系人主页 +func WithDocContactHomePage(url string) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + opt.Info.Contact.Url = url + } +} + +// WithDocServers 设置文档服务器列表 +func WithDocServers(serverList []*define.ServerItem) SetGenerateOption { + return func(opt *define.OpenapiDoc) { + if len(serverList) == 0 { + return + } + opt.Servers = serverList + } +} diff --git a/generate.go b/generate.go index 3c74f20..9ad4e15 100644 --- a/generate.go +++ b/generate.go @@ -25,48 +25,39 @@ import ( // Author : go_developer@163.com<白茶清欢> // // Date : 15:56 2024/7/22 -func NewOpenapiDoc(info *define.Info, servers []*define.ServerItem) *Generate { - if nil == info { - info = &define.Info{ +func NewOpenapiDoc(ofs ...SetGenerateOption) *Generate { + // 初始默认值 + docCfg := &define.OpenapiDoc{ + Openapi: consts.SwaggerDocVersion3, + Info: &define.Info{ Description: "openapi接口文档", Title: "openapi接口文档", TermsOfService: "", - Contact: nil, - License: nil, - Version: "0.0.1", - } + Contact: &define.Contact{ + Name: "研发人员(developer)", + Url: "", + Email: "", + }, + License: &define.License{ + Name: enums.LicenseApache20, + Url: enums.LicenseUrlTable[consts.LicenseApache20], + }, + Version: "0.0.1", + }, + Servers: []*define.ServerItem{}, + Components: &define.Components{Schemas: map[string]*define.Schema{}}, + Tags: make([]*define.TagItem, 0), + Paths: make(map[string]*define.PathConfig), } - if len(info.Version) == 0 { - info.Version = "0.0.1" - } - if nil == info.License { - info.License = &define.License{ - Name: consts.LicenseApache20, - Url: consts.LicenseUrlTable[consts.LicenseApache20], - } - } - if nil == info.Contact { - info.Contact = &define.Contact{ - Name: "研发人员(developer)", - Url: "", - Email: "", - } - } - if nil == servers { - servers = []*define.ServerItem{} + + for _, option := range ofs { + option(docCfg) } return &Generate{ readMethodList: []string{ http.MethodGet, http.MethodHead, http.MethodConnect, http.MethodOptions, http.MethodTrace, }, - docData: &define.OpenapiDoc{ - Openapi: consts.SwaggerDocVersion3, - Info: info, - Servers: servers, - Components: &define.Components{Schemas: map[string]*define.Schema{}}, - Tags: make([]*define.TagItem, 0), - Paths: make(map[string]*define.PathConfig), - }, + docData: docCfg, } } diff --git a/swagger/parser.go b/swagger/parser.go index 640c60a..66dd64c 100644 --- a/swagger/parser.go +++ b/swagger/parser.go @@ -15,6 +15,7 @@ import ( "strings" apiDocDefine "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/wrapper" ) diff --git a/swagger/run.go b/swagger/run.go index 8301d5c..66d969b 100644 --- a/swagger/run.go +++ b/swagger/run.go @@ -12,7 +12,9 @@ import ( "strings" "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/gateway/api-doc/enums" "git.zhangdeman.cn/gateway/api-doc/util" + "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/wrapper" ) @@ -25,7 +27,7 @@ func Generate(docConfig *define.SwaggerInput) (*define.Swagger, error) { formatDocConfig(docConfig) swaggerInfo := &define.Swagger{ Schemes: docConfig.Schemes, - Swagger: consts.SwaggerDocVersion2, + Swagger: enums.SwaggerDocVersion2.String(), Host: docConfig.Host, BasePath: docConfig.BasePath, Info: docConfig.Info, @@ -228,7 +230,7 @@ func generateParameterDefinitions(swaggerInfo *define.Swagger, uri string, paren if subPathArr[1] == "[]" { swaggerInfo.Definitions[parentPath].Properties[subPathArr[0]] = &define.SwaggerDefinitionProperty{ Description: paramConfig.Description, - Type: consts.SwaggerDataTypeArray, + Type: enums.SwaggerDataTypeArray.String(), Items: &define.SwaggerDefinitionPropertyItem{ Type: util.GetSwaggerType(paramConfig.Type), Ref: "", @@ -242,7 +244,7 @@ func generateParameterDefinitions(swaggerInfo *define.Swagger, uri string, paren } else { swaggerInfo.Definitions[parentPath].Properties[subPathArr[0]] = &define.SwaggerDefinitionProperty{ Description: "参数描述", - Type: consts.SwaggerDataTypeObject, + Type: enums.SwaggerDataTypeObject.String(), AllOf: []map[string]string{ { consts.SwaggerRefKey: getRefValue(parentPath + "." + subPathArr[0]),