diff --git a/common.go b/common.go index 6f3f664..4bb4848 100644 --- a/common.go +++ b/common.go @@ -9,9 +9,11 @@ package api_doc import ( "fmt" - "git.zhangdeman.cn/gateway/api-doc/define" - "git.zhangdeman.cn/zhangdeman/consts" "strings" + + "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/gateway/api-doc/enums" + "git.zhangdeman.cn/zhangdeman/consts" ) // GetUriPathParamList 获取uri参数列表 @@ -60,22 +62,22 @@ func GetDataType(docParamType string, formatType string) string { // format type 和内置的支持数据类型不一致, 根据文档类型进行转换 switch docParamType { - case consts.SwaggerDataTypeInteger: + case enums.SwaggerDataTypeInteger.String(): if formatType == consts.DataTypeInt.String() { return consts.DataTypeInt.String() } return consts.DataTypeInt.String() - case "string", "apikey": + case enums.SwaggerDataTypeString.String(), enums.SwaggerDataTypeString.String(): return consts.DataTypeString.String() - case "object": + case enums.SwaggerDataTypeObject.String(): return consts.DataTypeMapStrAny.String() - case "boolean": + case enums.SwaggerDataTypeObject.String(): return consts.DataTypeBool.String() - case "number", "float", "double", "float64": + case enums.SwaggerDataTypeNumber.String(), "float", "double", "float64": return consts.DataTypeFloat64.String() case "float32": return consts.DataTypeFloat32.String() - case "array": + case enums.SwaggerDataTypeArray.String(): if formatType == "integer" { return consts.DataTypeSliceInt.String() } else if formatType == "string" { @@ -89,22 +91,18 @@ func GetDataType(docParamType string, formatType string) string { } // GetParamLocation 获取参数位置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:02 2024/12/24 func GetParamLocation(docParamLocation string) consts.RequestDataLocation { docParamLocation = strings.ToLower(docParamLocation) switch docParamLocation { - case "query": + case enums.DocParamLocationQuery.String(): return consts.RequestDataLocationQuery - case "header": + case enums.DocParamLocationHeader.String(): return consts.RequestDataLocationHeader - case "cookie": + case enums.DocParamLocationCookie.String(): return consts.RequestDataLocationCookie - case "body": + case enums.DocParamLocationBody.String(): return consts.RequestDataLocationBody - case "path": + case enums.DocParamLocationPath.String(): return consts.RequestDataLocationUriPath default: return consts.RequestDataLocationQuery @@ -113,12 +111,12 @@ func GetParamLocation(docParamLocation string) consts.RequestDataLocation { // GetRealDefinitionsKey 通过schema下的 $ref 获取真实的 definitions key func GetRealDefinitionsKey(ref string) string { - return strings.TrimPrefix(ref, "#/definitions/") + return strings.TrimPrefix(ref, enums.RefPrefixSchemaDefinition.String()) } // GetRealResponseKey 通过schema下的 $ref 获取真实的 response key func GetRealResponseKey(ref string) string { - return strings.TrimPrefix(ref, "#/responses/") + return strings.TrimPrefix(ref, enums.RefPrefixSchemaResponse.String()) } // GetSuccessResponseConfig 获取成功的响应配置 @@ -133,7 +131,7 @@ func GetSuccessResponseConfig(resultConfig map[string]*define.SwaggerPathConfigR // DataTypeIsArray 判断数据类型是否为数组 func DataTypeIsArray(docDataType string) bool { - return strings.ToLower(docDataType) == "array" + return strings.ToLower(docDataType) == enums.SwaggerDataTypeArray.String() } // ExpandArrayParam 展开详细的数组配置 diff --git a/define/openapi.go b/define/openapi.go index d8a83d8..363f3b8 100644 --- a/define/openapi.go +++ b/define/openapi.go @@ -7,11 +7,9 @@ // Date : 2024-04-23 22:16 package define +import "git.zhangdeman.cn/gateway/api-doc/enums" + // OpenapiDoc openapi文档结构, 文档规范参见 : https://openapi.apifox.cn/ -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:16 2024/7/19 type OpenapiDoc struct { Openapi string `json:"openapi" required:"true"` // 必选. 这个字符串必须是开放 API 规范版本号提到的符合语义化版本号规范的版本号。openapi字段应该被工具或者客户端用来解释 OpenAPI 文档. Info *Info `json:"info,omitempty" required:"true"` // 必选。此字段提供 API 相关的元数据。相关工具可能需要这个字段。 @@ -22,19 +20,11 @@ type OpenapiDoc struct { } // Components 数据结构定义 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:22 2024/7/19 type Components struct { Schemas map[string]*Schema `json:"schemas"` // 数据结构定义 } // PathConfig ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 18:06 2024/7/19 type PathConfig struct { Get *PathItemOperationConfig `json:"get,omitempty"` // 定义适用于此路径的 GET 操作。 Put *PathItemOperationConfig `json:"put,omitempty"` // 定义适用于此路径的 PUT 操作。 @@ -51,10 +41,6 @@ type PathConfig struct { // 描述对一个路径可执行的有效操作。 // 依赖与 ACL constraints 的设置,一个Path Item可以是一个空对象, // 文档的读者仍然可以看到这个路径,但是他们将无法了解到对这个路径可用的任何操作和参数。 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:22 2024/7/19 type PathItemConfig struct { Ref string `json:"$ref"` // 指定对此路径的外部定义的引用,引用的格式必须符合 Path Item 对象 的格式,如果引用的外部定义和此对象内的其他定义有冲突,该如何处理冲突尚未被定义。 Summary string `json:"summary"` // 一个可选的简要总结字符串,用来描述此路径内包含的所有操作。 @@ -65,10 +51,6 @@ type PathItemConfig struct { } // PathItemOperationConfig 描述对路径的某个操作。 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:20 2024/7/19 type PathItemOperationConfig struct { Tags []string `json:"tags"` // 用于控制API文档的标签列表,标签可以用于在逻辑上分组对资源的操作或作为其它用途的先决条件。 Summary string `json:"summary"` // 对此操作行为的简短描述。 @@ -85,20 +67,12 @@ type PathItemOperationConfig struct { } // ExternalDocs 外部文档配置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:30 2024/7/19 type ExternalDocs struct { Url string `json:"url"` // 必选. 外部文档的URL地址,这个值必须是URL地址格式。 Description string `json:"description"` // 对引用的外部文档的简短描述。CommonMark syntax可以被用来呈现富文本格式. } // PathConfigParameter 参数配置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:29 2024/7/19 type PathConfigParameter struct { Name string `json:"name"` // 参数名称 In string `json:"in"` // 必选. 参数的位置,可能的值有 "query", "header", "path" 或 "cookie"。 @@ -114,10 +88,6 @@ type PathConfigParameter struct { } // Schema ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:32 2024/7/19 type Schema struct { Nullable bool `json:"nullable,omitempty"` // 对于定义的schema,允许发送 null 值。默认值是 false. Discriminator *SchemaDiscriminator `json:"discriminator,omitempty"` // 说白了, 就是一个字段可能是不同的数据结构。。。 @@ -145,10 +115,6 @@ type Schema struct { } // Property 是从 JSON Schema 提取出来的,但是做了一些调整以适应 OpenAPI Specification。 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:05 2024/7/19 type Property struct { Type any `json:"type,omitempty"` // 数据类型(string | []string), swagger本身的定义 Format string `json:"format,omitempty"` // 对应编程语言中的数据类型描述 @@ -171,10 +137,6 @@ type Property struct { } // PropertyXOf ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:13 2024/7/19 type PropertyXOf struct { Type string `json:"type,omitempty"` // 基础类型 Format string `json:"format,omitempty"` // 真实类型 @@ -186,20 +148,12 @@ type PropertyXOf struct { // SchemaDiscriminator 当一个 request bodies 或 response payloads 可以是多种 schemas 时,可以使用一个 discriminator 对象来帮助序列化、反序列化和校验 // discriminator 属性仅在与 oneOf, anyOf, allOf 这几个复合关键字之一一起使用时才合法. -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:48 2024/7/19 type SchemaDiscriminator struct { PropertyName string `json:"propertyName"` // 必选. 在 payload 中表示 discriminator 值的属性的名称。 Mapping map[string]string `json:"mapping"` // 一个映射 payload 中的值和 schema 名称或引用的对象。 } // XML 一个为 XML 模型定义微调过的元数据对象。 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:56 2024/7/19 type XML struct { Name string `json:"name"` // 替换用于描述元素/属性的结构特性的名称。当在 items 内定义时将会影响处于此列表中的每个元素的名称。当定义于 items 之上时将会影响它说包裹的元素且仅当 wrapped 是 true 时,如果 wrapped 是 false 时它将会被忽略 Namespace string `json:"namespace"` // 命名空间定义的 URI。其值必须是绝对 URI。 @@ -209,10 +163,6 @@ type XML struct { } // RequestBody 定义请求体 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:17 2024/7/19 type RequestBody struct { Required bool `json:"required"` // 指定请求体是不是应该被包含在请求中,默认值是false。 Description string `json:"description,omitempty"` // 对请求体的简要描述,可以包含使用示例,CommonMark syntax可以被用来呈现富文本格式 @@ -221,10 +171,6 @@ type RequestBody struct { } // Media 本质即为不一样 content_type 对应的数据结构定义 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:21 2024/7/19 type Media struct { Schema *Schema `json:"schema,omitempty"` // 定义此媒体类型的结构。 Example map[string]any `json:"example,omitempty"` // 媒体类型的示例。示例对象应该符合此媒体类型的格式, 这里指定的example对象 object is mutually exclusive of the examples object. 而且如果引用的schema也包含示例,在这里指定的example值将会覆盖schema提供的示例。 @@ -233,10 +179,6 @@ type Media struct { } // Encoding 一个编码定义仅适用于一个结构属性 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:28 2024/7/19 type Encoding struct { ContentType string `json:"content_type,omitempty"` // 对具体属性的 Content-Type的编码。默认值取决于属性的类型:application/octet-stream编码适用于binary格式的string;text/plain适用于其他原始值;application/json适用于object;对于array值类型的默认值取决于数组内元素的类型,默认值可以是明确的媒体类型(比如application/json), 或者通配符类型的媒体类型(比如image/*), 又或者是用分号分隔的两种媒体类型。 Headers map[string]*Header `json:"headers,omitempty"` // 提供附加信息的请求头键值对映射。比如Content-Disposition、Content-Type各自描述了不同的信息而且在这里将会被忽略,如果请求体的媒体类型不是multipart,这个属性将会被忽略。 @@ -257,10 +199,6 @@ type Encoding struct { type Header PathConfigParameter // Example ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:24 2024/7/19 type Example struct { Summary string `json:"summary,omitempty"` // example 的简要描述。 Description string `json:"description,omitempty"` // example 的详细描述。CommonMark syntax可以被用来呈现富文本格式. @@ -269,10 +207,6 @@ type Example struct { } // Response 响应的数据结构 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:38 2024/7/19 type Response struct { Description string `json:"description" required:"true"` // 必选. 对响应的简短描述。CommonMark syntax可以被用来呈现富文本格式. Headers map[string]*Header `json:"headers,omitempty"` // 映射HTTP头名称到其定义。RFC7230 规定了HTTP头名称不区分大小写。如果一个响应头使用"Content-Type"作为HTTP头名称,它会被忽略。 @@ -281,10 +215,6 @@ type Response struct { } // Info 信息 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:10 2024/4/19 type Info struct { Description string `json:"description,omitempty"` // 对应用的简短描述。 CommonMark syntax 可以被用来表示富文本呈现。 Title string `json:"title,omitempty" required:"true"` // 必选. 应用的名称。 @@ -295,10 +225,6 @@ type Info struct { } // Contact 联系人信息 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:08 2024/4/19 type Contact struct { Name string `json:"name,omitempty"` // 人或组织的名称。 Url string `json:"url,omitempty"` // 指向联系人信息的 URL 地址,必须是 URL 地址格式。 @@ -306,20 +232,12 @@ type Contact struct { } // License 开源协议 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:09 2024/4/19 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 对象结构 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:18 2024/7/19 type ServerItem struct { Url string `json:"url,omitempty" required:"true"` // 必选. 指向目标主机的 URL 地址。这个 URL 地址支持服务器变量而且可能是相对路径,表示主机路径是相对于本文档所在的路径。当一个变量被命名为类似{brackets}时需要替换此变量。 Description string `json:"description,omitempty"` // 一个可选的字符串,用来描述此 URL 地址。CommonMark syntax可以被用来呈现富文本格式. @@ -327,10 +245,6 @@ type ServerItem struct { } // ServerItemVariable ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:22 2024/7/19 type ServerItemVariable struct { Default string `json:"default,omitempty"` // 变量默认值 Description string `json:"description,omitempty"` // 变量描述 @@ -338,10 +252,6 @@ type ServerItemVariable struct { } // TagItem 每一个标签数据结构 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 12:18 2024/7/19 type TagItem struct { Name string `json:"name,omitempty"` // 标签名称 Description string `json:"description,omitempty"` // 标签描述 diff --git a/define/seagger_ui.go b/define/seagger_ui.go deleted file mode 100644 index df64281..0000000 --- a/define/seagger_ui.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package define ... -// -// Description : define ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2025-02-16 13:18 -package define - -const ( - SwaggerUIThemeDefault = "swaggerUI" // 文档默认主题 - SwaggerUIThemeKnife4go = "knife4go" // knife4go 主题 - SwaggerUIThemeYDocLucky = "ydoc-lucky-ui" // YDoc Lucky UI 主题: https://github.com/NoBugBoy/LuckyUI - SwaggerUIThemeRedocFree = "redoc-free" // redoc UI 主题, 开源免费版: https://github.com/Redocly/redoc -) diff --git a/enums/data_location.go b/enums/data_location.go new file mode 100644 index 0000000..76deb27 --- /dev/null +++ b/enums/data_location.go @@ -0,0 +1,22 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 00:34 +package enums + +type DocParamLocation string + +func (dpl DocParamLocation) String() string { + return string(dpl) +} + +const ( + DocParamLocationQuery DocParamLocation = "query" + DocParamLocationHeader DocParamLocation = "header" + DocParamLocationCookie DocParamLocation = "cookie" + DocParamLocationBody DocParamLocation = "body" + DocParamLocationPath DocParamLocation = "path" +) diff --git a/enums/data_type.go b/enums/data_type.go new file mode 100644 index 0000000..b2930cc --- /dev/null +++ b/enums/data_type.go @@ -0,0 +1,46 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-22 23:58 +package enums + +import ( + "strings" +) + +type SwaggerDataType string + +func (sdt SwaggerDataType) String() string { + return string(sdt) +} + +// MarshalJSON 支持序列化 +func (sdt SwaggerDataType) MarshalJSON() ([]byte, error) { + return []byte(`"` + sdt.String() + `"`), nil +} + +// UnmarshalJSON 支持反序列化 +func (sdt *SwaggerDataType) UnmarshalJSON(d []byte) error { + *sdt = SwaggerDataType(strings.Trim(string(d), `"`)) + return nil +} + +const ( + SwaggerDataTypeInteger SwaggerDataType = "integer" // 32 位有符号 + SwaggerDataTypeLong SwaggerDataType = "long" // 64 位有符号 + SwaggerDataTypeFloat SwaggerDataType = "number" + SwaggerDataTypeDouble SwaggerDataType = "number" + SwaggerDataTypeNumber SwaggerDataType = "number" + SwaggerDataTypeByte SwaggerDataType = "string" + SwaggerDataTypeBinary SwaggerDataType = "binary" // 任意 8 进制序列 + SwaggerDataTypeString SwaggerDataType = "string" + SwaggerDataTypeDate SwaggerDataType = "string" + SwaggerDataTypePassword SwaggerDataType = "password" + SwaggerDataTypeBoolean SwaggerDataType = "boolean" + SwaggerDataTypeArray SwaggerDataType = "array" + SwaggerDataTypeObject SwaggerDataType = "object" + SwaggerDataTypeApiKey SwaggerDataType = "apikey" +) 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/enums/ref.go b/enums/ref.go new file mode 100644 index 0000000..ba87494 --- /dev/null +++ b/enums/ref.go @@ -0,0 +1,20 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 00:40 +package enums + +// RefPrefix 各种ref引用的前缀定义 +type RefPrefix string + +func (rp RefPrefix) String() string { + return string(rp) +} + +const ( + RefPrefixSchemaDefinition RefPrefix = "#/definitions/" // schema下的 $ref 下 definitions 的前缀 + RefPrefixSchemaResponse RefPrefix = "#/responses/" // schema下的 $ref 下 response 的前缀 +) diff --git a/enums/ui_theme.go b/enums/ui_theme.go new file mode 100644 index 0000000..d2c4ced --- /dev/null +++ b/enums/ui_theme.go @@ -0,0 +1,21 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 01:03 +package enums + +type SwaggerUITheme string + +func (sut SwaggerUITheme) String() string { + return string(sut) +} + +const ( + SwaggerUIThemeDefault SwaggerUITheme = "swaggerUI" // 文档默认主题 + SwaggerUIThemeKnife4go SwaggerUITheme = "knife4go" // knife4go 主题 + SwaggerUIThemeYDocLucky SwaggerUITheme = "ydoc-lucky-ui" // YDoc Lucky UI 主题: https://github.com/NoBugBoy/LuckyUI + SwaggerUIThemeRedocFree SwaggerUITheme = "redoc-free" // redoc UI 主题, 开源免费版: https://github.com/Redocly/redoc +) diff --git a/enums/version.go b/enums/version.go new file mode 100644 index 0000000..2708718 --- /dev/null +++ b/enums/version.go @@ -0,0 +1,19 @@ +// Package enums ... +// +// Description : enums ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 00:50 +package enums + +type SwaggerVersion string + +func (sv SwaggerVersion) String() string { + return string(sv) +} + +const ( + SwaggerDocVersion2 SwaggerVersion = "2.0" + SwaggerDocVersion3 SwaggerVersion = "3.0.0" +) 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 fa4351f..9ad4e15 100644 --- a/generate.go +++ b/generate.go @@ -10,12 +10,14 @@ package api_doc import ( "errors" "fmt" - "git.zhangdeman.cn/gateway/api-doc/define" - "git.zhangdeman.cn/zhangdeman/consts" - "git.zhangdeman.cn/zhangdeman/wrapper" "net/http" "reflect" "strings" + + "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/gateway/api-doc/enums" + "git.zhangdeman.cn/zhangdeman/consts" + "git.zhangdeman.cn/zhangdeman/wrapper" ) // NewOpenapiDoc ... @@ -23,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, } } @@ -82,45 +75,7 @@ func (g *Generate) Doc() *define.OpenapiDoc { return g.docData } -// SetLicense 设置文档协议 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:56 2024/8/14 -func (g *Generate) SetLicense(name string, url string) { - g.docData.Info.License.Name = name - g.docData.Info.License.Url = url -} - -// AddTag 新增tag -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:23 2024/8/14 -func (g *Generate) AddTag(tagName string, tagDesc string) { - isHasTag := false - for _, item := range g.docData.Tags { - if item.Name == tagName { - if len(tagDesc) > 0 { - item.Description = tagDesc - } - isHasTag = true - break - } - } - if !isHasTag { - g.docData.Tags = append(g.docData.Tags, &define.TagItem{ - Name: tagName, - Description: tagDesc, - }) - } -} - // AddServer 添加server -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:45 2024/8/14 func (g *Generate) AddServer(serverDomain string, serverDesc string, serverVariable map[string]*define.ServerItemVariable) { if nil == serverVariable { serverVariable = make(map[string]*define.ServerItemVariable) @@ -149,35 +104,7 @@ func (g *Generate) AddServer(serverDomain string, serverDesc string, serverVaria } } -// AddApi 新增Api -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 15:04 2024/8/14 -// -// baseCfg : 接口基础配置, 示例数据 -// -// &define.UriBaseConfig{ -// Uri: "/foo/bar", -// Method: http.MethodPost, -// ContentType: ["application/json"], -// TagList: []string{"测试标签"}, -// Summary: "这是一份示例基础配置", -// Description: "这是一份示例基础配置", -// } -// -// paramList : 参数列表 -// -// resultList : 返回值列表 -func (g *Generate) AddApi(baseCfg *define.UriBaseConfig, paramList []*define.ParamConfig, resultList []*define.ResultConfig) error { - return nil -} - // AddApiFromInAndOut 通过请求参数的 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:22 2025/2/9 func (g *Generate) AddApiFromInAndOut(uriPrefix string, paramType reflect.Type, resultType reflect.Type) error { if paramType.Kind() == reflect.Ptr { paramType = paramType.Elem() @@ -260,10 +187,6 @@ func (g *Generate) setApiDoc(baseCfg *define.UriBaseConfig, apiDocCfg *define.Pa } // getApiDocBaseCfg 获取接口文档的基础配置 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:10 2025/2/14 func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType reflect.Type) *define.PathItemOperationConfig { cfg := &define.PathItemOperationConfig{ Tags: baseCfg.TagList, @@ -279,7 +202,7 @@ func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType ref Ref: "", }, Responses: map[string]*define.Response{ - fmt.Sprintf("%v", http.StatusOK): &define.Response{ + fmt.Sprintf("%v", http.StatusOK): { Content: map[string]*define.Media{}, }, }, @@ -295,12 +218,12 @@ func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType ref param = strings.TrimSuffix(param, "}") cfg.Parameters = append(cfg.Parameters, &define.PathConfigParameter{ Name: param, - In: consts.SwaggerParameterInPath, + In: enums.DocParamLocationPath.String(), Description: param, Required: true, Deprecated: false, Schema: &define.Schema{ - Type: consts.SwaggerDataTypeString, + Type: enums.SwaggerDataTypeString.String(), Format: consts.DataTypeString.String(), }, AllowEmptyValue: false, @@ -311,10 +234,6 @@ func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType ref } // ParseReadConfigParam 解析get类请求参数 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 11:55 2025/2/14 func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseReqCfg *define.PathItemOperationConfig, inputType reflect.Type) { if inputType.Kind() == reflect.Ptr { inputType = inputType.Elem() diff --git a/go.mod b/go.mod index aefb63d..5d41072 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.23.0 toolchain go1.24.1 require ( - git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995 git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9 git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 github.com/gin-gonic/gin v1.10.1 diff --git a/go.sum b/go.sum index fc794b7..e56fe59 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995 h1:LmPRAf0AsxRVFPibdpZR89ajlsz8hof2IvMMyTqiEq4= -git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc= +git.zhangdeman.cn/zhangdeman/api-doc/enums v0.0.0-20250425024726-cc17224cb995 h1:LmPRAf0AsxRVFPibdpZR89ajlsz8hof2IvMMyTqiEq4= +git.zhangdeman.cn/zhangdeman/api-doc/enums v0.0.0-20250425024726-cc17224cb995/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI= git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9 h1:/GLQaFoLb+ciHOtAS2BIyPNnf4O5ME3AC5PUaJY9kfs= diff --git a/parser.go b/parser.go index 5cd81a9..3547b8e 100644 --- a/parser.go +++ b/parser.go @@ -9,6 +9,7 @@ package api_doc import ( "errors" + "git.zhangdeman.cn/gateway/api-doc/define" "git.zhangdeman.cn/zhangdeman/serialize" ) diff --git a/struct_field.go b/struct_field.go index 97e603f..3c451d4 100644 --- a/struct_field.go +++ b/struct_field.go @@ -8,10 +8,11 @@ package api_doc import ( - "git.zhangdeman.cn/gateway/api-doc/define" "reflect" "strconv" "strings" + + "git.zhangdeman.cn/gateway/api-doc/define" ) var ( diff --git a/swagger.go b/swagger.go index a05fdb4..ccf499a 100644 --- a/swagger.go +++ b/swagger.go @@ -9,11 +9,12 @@ package api_doc import ( "errors" + "net/http" + "strings" + "git.zhangdeman.cn/gateway/api-doc/define" "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/serialize" - "net/http" - "strings" ) // ParseSwagger2 解析swagger2.0版本文档 diff --git a/swagger/parser.go b/swagger/parser.go index 868de31..66dd64c 100644 --- a/swagger/parser.go +++ b/swagger/parser.go @@ -10,12 +10,13 @@ package swagger import ( "errors" "fmt" - apiDocDefine "git.zhangdeman.cn/gateway/api-doc/define" - "git.zhangdeman.cn/zhangdeman/consts" - "git.zhangdeman.cn/zhangdeman/wrapper" "net/http" "sort" "strings" + + apiDocDefine "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/zhangdeman/consts" + "git.zhangdeman.cn/zhangdeman/wrapper" ) // HandleOpenapiDocRes ... diff --git a/swagger/run.go b/swagger/run.go index 11c7a39..66d969b 100644 --- a/swagger/run.go +++ b/swagger/run.go @@ -8,12 +8,14 @@ package swagger import ( + "net/http" + "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" - "net/http" - "strings" ) // Generate 生成文档 @@ -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]), @@ -288,7 +290,7 @@ func generateParameterDefinitions(swaggerInfo *define.Swagger, uri string, paren AllOf: nil, } if itemSwaggerDefinition.Type == consts.SwaggerDataTypeObject { - itemSwaggerDefinition.AllOf = []map[string]string{map[string]string{ + itemSwaggerDefinition.AllOf = []map[string]string{{ consts.SwaggerRefKey: getRefValue(parentPath + "." + subPathArr[0]), }} } else if itemSwaggerDefinition.Type == consts.SwaggerDataTypeArray { diff --git a/swagger/run_test.go b/swagger/run_test.go index c204afc..5779d94 100644 --- a/swagger/run_test.go +++ b/swagger/run_test.go @@ -10,10 +10,10 @@ package swagger import ( "encoding/json" "fmt" - "git.zhangdeman.cn/gateway/api-doc/define" - "git.zhangdeman.cn/zhangdeman/consts" "net/http" "testing" + + "git.zhangdeman.cn/gateway/api-doc/define" ) func TestGenerate(t *testing.T) { @@ -37,7 +37,7 @@ func TestGenerate(t *testing.T) { Version: "", }, PathConfigList: []*define.SwaggerPathInput{ - &define.SwaggerPathInput{ + { Uri: "/test", Method: http.MethodPost, ContentType: consts.MimeTypeJson, @@ -45,7 +45,7 @@ func TestGenerate(t *testing.T) { Description: "测试接口", TagList: []string{"测试接口生成"}, ParameterList: []*define.SwaggerParameterInput{ - &define.SwaggerParameterInput{ + { Type: consts.DataTypeString.String(), Description: "姓名", Name: "name", @@ -53,7 +53,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: []interface{}{"zhang", "de", "man"}, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeString.String(), Description: "性别", Name: "person.sex", @@ -61,7 +61,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: []interface{}{"man", "woman", "other"}, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeString.String(), Description: "性别", Name: "person.job.list.[]", @@ -69,7 +69,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: nil, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeInt.String(), Description: "年份", Name: "person.job.year.[]", @@ -77,7 +77,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: nil, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeInt.String(), Description: "测试工作", Name: "person.job.test", @@ -85,7 +85,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: nil, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeInt.String(), Description: "年龄", Name: "age", @@ -93,7 +93,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: []interface{}{18, 19, 20}, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeInt.String(), Description: "年龄", Name: "test_list.[].age", @@ -101,7 +101,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: []interface{}{18, 19, 20}, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeString.String(), Description: "年龄", Name: "test_list.[].name", @@ -109,7 +109,7 @@ func TestGenerate(t *testing.T) { Required: true, EnumList: nil, }, - &define.SwaggerParameterInput{ + { Type: consts.DataTypeMapAnyAny.String(), Description: "测试global_map", Name: "obj", @@ -119,32 +119,32 @@ func TestGenerate(t *testing.T) { }, }, ResponseList: []*define.SwaggerResponseInput{ - &define.SwaggerResponseInput{ + { Code: "200", Description: "成功", List: []*define.SwaggerResponseItemInput{ - &define.SwaggerResponseItemInput{ + { Type: consts.DataTypeString.String(), Description: "姓名", Field: "nick_name", IsRequired: false, }, - &define.SwaggerResponseItemInput{ + { Type: consts.DataTypeString.String(), Description: "昵称", Field: "person.nick_name", - IsRequired: false, - }, - &define.SwaggerResponseItemInput{ - Type: consts.DataTypeMapAnyAny.String(), - Description: "测试返回生成map", - Field: "obj", - IsRequired: false, + IsRequired: false, + }, + { + Type: consts.DataTypeMapAnyAny.String(), + Description: "测试返回生成map", + Field: "obj", + IsRequired: false, + }, + }, + }, }, }, - }, - }, - }, }, }) byteData, _ := json.MarshalIndent(res, "", "\t") diff --git a/swagger_ui.go b/swagger_ui.go index b29fb49..0235dbb 100644 --- a/swagger_ui.go +++ b/swagger_ui.go @@ -8,32 +8,24 @@ package api_doc import ( - "embed" "fmt" + "net/http" + "path/filepath" + "strings" + "git.zhangdeman.cn/gateway/api-doc/define" + "git.zhangdeman.cn/gateway/api-doc/enums" + "git.zhangdeman.cn/gateway/api-doc/theme" "git.zhangdeman.cn/zhangdeman/consts" "github.com/gin-gonic/gin" knife4goFiles "github.com/go-webtools/knife4go" knife4goGin "github.com/go-webtools/knife4go/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" - "net/http" - "path/filepath" - "strings" ) -//go:embed ydoc-lucky-ui/* -var ydocUIFiles embed.FS - -//go:embed redoc-free/index.html -var redocFreeIndexContent string - // NewSwaggerUI ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:21 2025/2/15 -func NewSwaggerUI(info *define.Info, servers []*define.ServerItem, uiTheme string) *SwaggerUI { +func NewSwaggerUI(info *define.Info, servers []*define.ServerItem, uiTheme enums.SwaggerUITheme) *SwaggerUI { return &SwaggerUI{ docInstance: NewOpenapiDoc(info, servers), uiTheme: uiTheme, @@ -41,26 +33,18 @@ func NewSwaggerUI(info *define.Info, servers []*define.ServerItem, uiTheme strin } type SwaggerUI struct { - docInstance *Generate // 文档实例 - uiTheme string // 文档主题, swaggerUI / knife4go, 默认 knife4go + docInstance *Generate // 文档实例 + uiTheme enums.SwaggerUITheme // 文档主题, swaggerUI / knife4go, 默认 knife4go router *gin.Engine baseUri string } // DocInstance 文档实例 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 13:23 2025/2/16 func (su *SwaggerUI) DocInstance() *Generate { return su.docInstance } // RegisterHandler ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 15:00 2025/2/16 func (su *SwaggerUI) RegisterHandler(router *gin.Engine, baseUri string) { su.router = router baseUri = strings.TrimRight(baseUri, "/") @@ -80,7 +64,7 @@ func (su *SwaggerUI) RegisterHandler(router *gin.Engine, baseUri string) { { "name": "服务文档", "url": "doc.json", - "swaggerVersion": consts.SwaggerDocVersion3, + "swaggerVersion": enums.SwaggerDocVersion3.String(), }, }) ctx.Abort() @@ -92,7 +76,7 @@ func (su *SwaggerUI) RegisterHandler(router *gin.Engine, baseUri string) { { "name": "服务文档", "url": baseUri + "/doc.json", - "swaggerVersion": consts.SwaggerDocVersion3, + "swaggerVersion": enums.SwaggerDocVersion3.String(), }, }) // ctx.JSON(http.StatusOK, swaggerInstance.docInstance.Data()) @@ -100,20 +84,16 @@ func (su *SwaggerUI) RegisterHandler(router *gin.Engine, baseUri string) { } // Handler 访问文档的接口处理 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:34 2025/2/15 func (su *SwaggerUI) Handler() func(ctx *gin.Context) { switch su.uiTheme { - case define.SwaggerUIThemeKnife4go: + case enums.SwaggerUIThemeKnife4go: return su.HandleKnife4goUI() - case define.SwaggerUIThemeYDocLucky: + case enums.SwaggerUIThemeYDocLucky: // YDoc-Lucky-UI 主题处理 return su.HandleLuckyUI() - case define.SwaggerUIThemeDefault: + case enums.SwaggerUIThemeDefault: return su.HandleSwaggerUI() - case define.SwaggerUIThemeRedocFree: + case enums.SwaggerUIThemeRedocFree: // redoc免费版 return su.HandleRedocFreeUI() default: @@ -122,15 +102,11 @@ func (su *SwaggerUI) Handler() func(ctx *gin.Context) { } // HandleLuckyUI ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:04 2025/2/16 func (su *SwaggerUI) HandleLuckyUI() func(ctx *gin.Context) { // su.router.StaticFS(su.baseUri+"/assets", http.FS(ydocUIFiles)) return func(ctx *gin.Context) { fileRealPath := strings.TrimPrefix(ctx.Request.RequestURI, su.baseUri) - byteData, _ := ydocUIFiles.ReadFile(filepath.Join(define.SwaggerUIThemeYDocLucky, fileRealPath)) + byteData, _ := theme.YdocUIFiles.ReadFile(filepath.Join(enums.SwaggerUIThemeYDocLucky.String(), fileRealPath)) if strings.HasSuffix(ctx.Request.RequestURI, "html") { byteData = []byte(strings.ReplaceAll(string(byteData), "{{BASE_URI}}", su.baseUri)) } @@ -141,17 +117,13 @@ func (su *SwaggerUI) HandleLuckyUI() func(ctx *gin.Context) { } else if strings.HasSuffix(ctx.Request.RequestURI, "js") { contentType = "application/javascript" } - ctx.Header("Content-Type", contentType) + ctx.Header(consts.HeaderKeyContentType.String(), contentType) ctx.String(http.StatusOK, string(byteData)) ctx.Abort() } } // HandleKnife4goUI ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:38 2025/2/15 func (su *SwaggerUI) HandleKnife4goUI() func(ctx *gin.Context) { resetOption := func(cfg *knife4goGin.Config) { if nil == cfg { @@ -163,19 +135,11 @@ func (su *SwaggerUI) HandleKnife4goUI() func(ctx *gin.Context) { } // HandleSwaggerUI ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:41 2025/2/15 func (su *SwaggerUI) HandleSwaggerUI() func(ctx *gin.Context) { return ginSwagger.WrapHandler(swaggerFiles.Handler) } // HandleRedocFreeUI 处理redoc_free主题 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:40 2025/2/18 func (su *SwaggerUI) HandleRedocFreeUI() func(ctx *gin.Context) { return func(ctx *gin.Context) { // TODO : 这部分数据支持外部传参替换 @@ -186,10 +150,10 @@ func (su *SwaggerUI) HandleRedocFreeUI() func(ctx *gin.Context) { "{{REDOC_STANDALONE_JS}}": "https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js", } for k, v := range replaceTable { - redocFreeIndexContent = strings.ReplaceAll(redocFreeIndexContent, k, v) + theme.RedocFreeIndexContent = strings.ReplaceAll(theme.RedocFreeIndexContent, k, v) } - ctx.Header("Content-Type", "text/html; charset=utf-8") - ctx.String(http.StatusOK, redocFreeIndexContent) + ctx.Header(consts.HeaderKeyContentType.String(), "text/html; charset=utf-8") + ctx.String(http.StatusOK, theme.RedocFreeIndexContent) ctx.Abort() } } diff --git a/theme/embed.go b/theme/embed.go new file mode 100644 index 0000000..1c7698f --- /dev/null +++ b/theme/embed.go @@ -0,0 +1,16 @@ +// Package theme ... +// +// Description : theme ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-08-23 09:23 +package theme + +import "embed" + +//go:embed ydoc-lucky-ui/* +var YdocUIFiles embed.FS + +//go:embed redoc-free/index.html +var RedocFreeIndexContent string diff --git a/redoc-free/index.html b/theme/redoc-free/index.html similarity index 100% rename from redoc-free/index.html rename to theme/redoc-free/index.html diff --git a/ydoc-lucky-ui/assets/Api.525b760d.css b/theme/ydoc-lucky-ui/assets/Api.525b760d.css similarity index 100% rename from ydoc-lucky-ui/assets/Api.525b760d.css rename to theme/ydoc-lucky-ui/assets/Api.525b760d.css diff --git a/ydoc-lucky-ui/assets/Api.73b14880.js b/theme/ydoc-lucky-ui/assets/Api.73b14880.js similarity index 100% rename from ydoc-lucky-ui/assets/Api.73b14880.js rename to theme/ydoc-lucky-ui/assets/Api.73b14880.js diff --git a/ydoc-lucky-ui/assets/FirstPage.1d240e81.js b/theme/ydoc-lucky-ui/assets/FirstPage.1d240e81.js similarity index 100% rename from ydoc-lucky-ui/assets/FirstPage.1d240e81.js rename to theme/ydoc-lucky-ui/assets/FirstPage.1d240e81.js diff --git a/ydoc-lucky-ui/assets/FirstPage.48bcf13f.css b/theme/ydoc-lucky-ui/assets/FirstPage.48bcf13f.css similarity index 100% rename from ydoc-lucky-ui/assets/FirstPage.48bcf13f.css rename to theme/ydoc-lucky-ui/assets/FirstPage.48bcf13f.css diff --git a/ydoc-lucky-ui/assets/Manager.02a611ee.js b/theme/ydoc-lucky-ui/assets/Manager.02a611ee.js similarity index 100% rename from ydoc-lucky-ui/assets/Manager.02a611ee.js rename to theme/ydoc-lucky-ui/assets/Manager.02a611ee.js diff --git a/ydoc-lucky-ui/assets/MethodTrace.9051cb05.js b/theme/ydoc-lucky-ui/assets/MethodTrace.9051cb05.js similarity index 100% rename from ydoc-lucky-ui/assets/MethodTrace.9051cb05.js rename to theme/ydoc-lucky-ui/assets/MethodTrace.9051cb05.js diff --git a/ydoc-lucky-ui/assets/Models.a928c1a8.js b/theme/ydoc-lucky-ui/assets/Models.a928c1a8.js similarity index 100% rename from ydoc-lucky-ui/assets/Models.a928c1a8.js rename to theme/ydoc-lucky-ui/assets/Models.a928c1a8.js diff --git a/ydoc-lucky-ui/assets/Share.3315ee0c.js b/theme/ydoc-lucky-ui/assets/Share.3315ee0c.js similarity index 100% rename from ydoc-lucky-ui/assets/Share.3315ee0c.js rename to theme/ydoc-lucky-ui/assets/Share.3315ee0c.js diff --git a/ydoc-lucky-ui/assets/icon.a080a8a4.svg b/theme/ydoc-lucky-ui/assets/icon.a080a8a4.svg similarity index 100% rename from ydoc-lucky-ui/assets/icon.a080a8a4.svg rename to theme/ydoc-lucky-ui/assets/icon.a080a8a4.svg diff --git a/ydoc-lucky-ui/assets/index.4ac3587a.js b/theme/ydoc-lucky-ui/assets/index.4ac3587a.js similarity index 100% rename from ydoc-lucky-ui/assets/index.4ac3587a.js rename to theme/ydoc-lucky-ui/assets/index.4ac3587a.js diff --git a/ydoc-lucky-ui/assets/index.5b18e4ae.css b/theme/ydoc-lucky-ui/assets/index.5b18e4ae.css similarity index 100% rename from ydoc-lucky-ui/assets/index.5b18e4ae.css rename to theme/ydoc-lucky-ui/assets/index.5b18e4ae.css diff --git a/ydoc-lucky-ui/assets/title.8b763cb0.png b/theme/ydoc-lucky-ui/assets/title.8b763cb0.png similarity index 100% rename from ydoc-lucky-ui/assets/title.8b763cb0.png rename to theme/ydoc-lucky-ui/assets/title.8b763cb0.png diff --git a/ydoc-lucky-ui/assets/vendor.0513d345.css b/theme/ydoc-lucky-ui/assets/vendor.0513d345.css similarity index 100% rename from ydoc-lucky-ui/assets/vendor.0513d345.css rename to theme/ydoc-lucky-ui/assets/vendor.0513d345.css diff --git a/ydoc-lucky-ui/assets/vendor.08310185.js b/theme/ydoc-lucky-ui/assets/vendor.08310185.js similarity index 100% rename from ydoc-lucky-ui/assets/vendor.08310185.js rename to theme/ydoc-lucky-ui/assets/vendor.08310185.js diff --git a/ydoc-lucky-ui/favicon.ico b/theme/ydoc-lucky-ui/favicon.ico similarity index 100% rename from ydoc-lucky-ui/favicon.ico rename to theme/ydoc-lucky-ui/favicon.ico diff --git a/ydoc-lucky-ui/index.html b/theme/ydoc-lucky-ui/index.html similarity index 100% rename from ydoc-lucky-ui/index.html rename to theme/ydoc-lucky-ui/index.html diff --git a/util/tool.go b/util/tool.go index 4419a44..1bcf568 100644 --- a/util/tool.go +++ b/util/tool.go @@ -8,9 +8,10 @@ package util import ( - "git.zhangdeman.cn/zhangdeman/consts" "net/http" "strings" + + "git.zhangdeman.cn/zhangdeman/consts" ) // GetParameterDefaultLocation 获取参数的默认位置 diff --git a/validate_rule.go b/validate_rule.go index 9b2443e..144bbd0 100644 --- a/validate_rule.go +++ b/validate_rule.go @@ -8,10 +8,11 @@ package api_doc import ( - "git.zhangdeman.cn/zhangdeman/consts" "reflect" "strconv" "strings" + + "git.zhangdeman.cn/zhangdeman/consts" ) var ( @@ -33,10 +34,6 @@ func (r validateRule) IsRequired(structField reflect.StructField) bool { } // Enum 获取枚举值 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 17:23 2025/2/13 func (r validateRule) Enum(structField reflect.StructField) []any { ruleTable := r.getValidateRuleTable(structField) oneOfValue, _ := ruleTable[consts.ValidatorRuleCommonOneOf.String()] @@ -79,10 +76,6 @@ func (r validateRule) Enum(structField reflect.StructField) []any { } // Minimum 最小值 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 21:51 2025/2/18 func (r validateRule) Minimum(structField reflect.StructField) *int64 { ruleTable := r.getValidateRuleTable(structField) var ( @@ -118,10 +111,6 @@ func (r validateRule) Minimum(structField reflect.StructField) *int64 { } // Maximum 最大值 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 22:00 2025/2/18 func (r validateRule) Maximum(structField reflect.StructField) *int64 { ruleTable := r.getValidateRuleTable(structField) var ( @@ -157,10 +146,6 @@ func (r validateRule) Maximum(structField reflect.StructField) *int64 { } // getValidateRuleTable 解析验证规则表 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 15:29 2025/2/13 func (r validateRule) getValidateRuleTable(structField reflect.StructField) map[string]string { res := map[string]string{} ruleStr := ParseStructFieldTag.GetValidateRule(structField)