api-doc/swagger/run.go

292 lines
11 KiB
Go

// Package swagger ...
//
// Description : swagger ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2024-04-19 18:16
package swagger
import (
"git.zhangdeman.cn/gateway/api-doc/define"
"git.zhangdeman.cn/gateway/api-doc/util"
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/wrapper"
"net/http"
"strings"
)
// Generate 生成文档
//
// Author : zhangdeman001@ke.com<张德满>
//
// Date : 18:17 2024/4/19
func Generate(docConfig *define.SwaggerInput) (*define.Swagger, error) {
formatDocConfig(docConfig)
swaggerInfo := &define.Swagger{
Schemes: docConfig.Schemes,
Swagger: define.SwaggerVersion2,
Host: docConfig.Host,
BasePath: docConfig.BasePath,
Info: docConfig.Info,
Paths: map[string]map[string]*define.SwaggerPathConfig{},
Definitions: map[string]*define.SwaggerDefinition{},
}
generatePathConfig(swaggerInfo, docConfig)
return swaggerInfo, nil
}
// formatDocConfig 格式化填充dock配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:54 2024/4/22
func formatDocConfig(docConfig *define.SwaggerInput) {
if len(docConfig.Schemes) == 0 {
docConfig.Schemes = []string{consts.SchemeHTTP}
}
docConfig.Host = wrapper.String(docConfig.Host).ReplaceChar(map[string]string{
"http://": "",
"https://": "",
}).Value()
for _, itemPath := range docConfig.PathConfigList {
// 默认请求类型 application/json
itemPath.ContentType = strings.TrimSpace(itemPath.ContentType)
itemPath.ContentType = wrapper.TernaryOperator.String(len(itemPath.ContentType) == 0, consts.MimeTypeJson, wrapper.String(itemPath.ContentType)).Value()
// 默认post请求
itemPath.Method = strings.TrimSpace(itemPath.Method)
itemPath.Method = wrapper.TernaryOperator.String(len(itemPath.ContentType) == 0, wrapper.String(strings.ToLower(http.MethodPost)), wrapper.String(strings.ToLower(itemPath.Method))).Value()
// 默认summary
itemPath.Summary = strings.TrimSpace(itemPath.Summary)
itemPath.Summary = wrapper.TernaryOperator.String(len(itemPath.Summary) == 0, wrapper.String("接口 : "+itemPath.Uri), wrapper.String(itemPath.Summary)).Value()
// 默认标签
itemPath.TagList = wrapper.TernaryOperator.Array(len(itemPath.TagList) == 0, wrapper.ArrayType([]string{"未分组"}), wrapper.ArrayType(itemPath.TagList)).ToStringSlice()
for _, itemParam := range itemPath.ParameterList {
// 填充默认参数位置
itemParam.In = strings.TrimSpace(itemParam.In)
itemParam.In = wrapper.TernaryOperator.String(len(itemParam.In) == 0, wrapper.String(util.GetParameterDefaultLocation(itemPath.Method)), wrapper.String(itemParam.In)).Value()
// 参数类型没填, 按照字符串处理
itemParam.Type = strings.TrimSpace(itemParam.Type)
itemParam.Type = wrapper.TernaryOperator.String(len(itemParam.Type) == 0, wrapper.String(itemParam.Type), wrapper.String(itemParam.Type)).Value()
// 参数描述
itemParam.Description = strings.TrimSpace(itemParam.Description)
itemParam.Description = wrapper.TernaryOperator.String(len(itemParam.Description) == 0, wrapper.String(itemParam.Type+" : "+itemParam.Name), wrapper.String(itemParam.Description)).Value()
}
for _, itemResponseConfig := range itemPath.ResponseList {
for _, itemResponse := range itemResponseConfig.List {
// 默认返回数据类型
itemResponse.Type = strings.TrimSpace(itemResponse.Type)
itemResponse.Type = wrapper.TernaryOperator.String(len(itemResponse.Type) == 0, consts.DataTypeString, wrapper.String(itemResponse.Type)).Value()
// 填充默认描述
itemResponse.Description = strings.TrimSpace(itemResponse.Description)
itemResponse.Description = wrapper.TernaryOperator.String(len(itemResponse.Description) == 0, wrapper.String(itemResponse.Type+" : "+itemResponse.Field), wrapper.String(itemResponse.Description)).Value()
}
}
}
}
// generatePathConfig 生成接口配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:00 2024/4/22
func generatePathConfig(swaggerInfo *define.Swagger, docConfig *define.SwaggerInput) {
for _, itemPath := range docConfig.PathConfigList {
itemPath.Uri = getUri(itemPath.Uri)
if _, exist := swaggerInfo.Paths[itemPath.Uri]; !exist {
swaggerInfo.Paths[itemPath.Uri] = map[string]*define.SwaggerPathConfig{}
}
// 处理请求类型的配置
swaggerInfo.Paths[itemPath.Uri][itemPath.Method] = &define.SwaggerPathConfig{
Description: itemPath.Description,
Consumes: []string{itemPath.ContentType},
Tags: itemPath.TagList,
Summary: itemPath.Summary,
Parameters: make([]*define.SwaggerPathConfigParameter, 0),
Responses: make(map[string]*define.SwaggerPathConfigResponse),
}
// 生成参数配置
generatePathParameterConfig(swaggerInfo, itemPath)
}
}
// generatePathParameterConfig 生成接口的参数配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:09 2024/4/22
func generatePathParameterConfig(swaggerInfo *define.Swagger, pathConfig *define.SwaggerPathInput) {
swaggerInfo.Paths[pathConfig.Uri][pathConfig.Method].Parameters = make([]*define.SwaggerPathConfigParameter, 0)
hasDealTable := map[string]bool{}
// hasDealResponseTable := map[string]bool{}
for _, itemParamInput := range pathConfig.ParameterList {
if len(itemParamInput.Name) == 0 {
// 未指定参数名, 忽略
continue
}
// name 可能是 x.x.x 递归数组, 或者 x.x.[].x
namePath := strings.Split(itemParamInput.Name, ".")
realParamName := namePath[0]
parentPath := ""
if !strings.Contains(realParamName, ".") {
realParamName = "jsonBody"
parentPath = pathConfig.Uri + ".jsonBody"
}
generateParameterDefinitions(swaggerInfo, pathConfig.Uri, parentPath, itemParamInput.Name, itemParamInput)
if _, exist := hasDealTable[namePath[0]]; !exist {
hasDealTable[namePath[0]] = true
generateParam := &define.SwaggerPathConfigParameter{
Type: itemParamInput.Type,
Description: itemParamInput.Description,
Name: realParamName,
In: itemParamInput.In,
Required: itemParamInput.Required,
Schema: map[string]string{},
}
if len(parentPath) > 0 {
generateParam.Schema["$ref"] = "#/definitions/" + strings.TrimLeft(pathConfig.Uri, "/") + ".jsonBody"
}
swaggerInfo.Paths[pathConfig.Uri][pathConfig.Method].Parameters = append(swaggerInfo.Paths[pathConfig.Uri][pathConfig.Method].Parameters, generateParam)
}
}
/*for _, itemResponseConfig := range pathConfig.ResponseList {
for _, itemResponseInput := range itemResponseConfig.List {
if len(itemResponseInput.Field) == 0 {
// 未指定参数名, 忽略
continue
}
// name 可能是 x.x.x 递归数组, 或者 x.x.[].x
outputDefine := pathConfig.Uri + "." + itemResponseConfig.Code + ".output"
generateResponseDefinitions(swaggerInfo, pathConfig.Uri, outputDefine, itemResponseInput.Field, itemResponseInput)
namePath := strings.Split(itemResponseInput.Field, ".")
if _, exist := hasDealResponseTable[namePath[0]]; !exist {
hasDealResponseTable[namePath[0]] = true
swaggerInfo.Paths[pathConfig.Uri][pathConfig.Method].Responses[itemResponseConfig.Code] = &define.SwaggerPathConfigResponse{
Description: itemResponseInput.Description,
Schema: map[string]string{
"$ref": "#/definitions" + outputDefine,
},
}
}
}
}*/
}
// generateParameterDefinitions 生成请求参数的描述
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:06 2024/4/22
func generateParameterDefinitions(swaggerInfo *define.Swagger, uri string, parentPath string, subPath string, paramConfig *define.SwaggerParameterInput) {
if nil == swaggerInfo.Definitions {
swaggerInfo.Definitions = map[string]*define.SwaggerDefinition{}
}
subPathArr := strings.Split(subPath, ".")
if _, exist := swaggerInfo.Definitions[parentPath]; !exist && len(parentPath) > 0 {
swaggerInfo.Definitions[parentPath] = &define.SwaggerDefinition{
Type: "object",
Required: make([]string, 0),
Properties: make(map[string]*define.SwaggerDefinitionProperty),
}
}
if len(subPathArr) == 1 {
if paramConfig.In != strings.ToLower(consts.RequestLocationBody) {
// 长度为1, 还不在 body, 无需生成结构体
return
}
if _, exist := swaggerInfo.Definitions[parentPath]; !exist {
swaggerInfo.Definitions[parentPath] = &define.SwaggerDefinition{
Type: "object",
Required: make([]string, 0),
Properties: make(map[string]*define.SwaggerDefinitionProperty),
}
}
swaggerInfo.Definitions[parentPath].Type = paramConfig.Type
if paramConfig.Required {
swaggerInfo.Definitions[parentPath].Required = append(swaggerInfo.Definitions[parentPath].Required, paramConfig.Name)
}
if len(parentPath) > 0 {
swaggerInfo.Definitions[parentPath].Properties[paramConfig.Name] = &define.SwaggerDefinitionProperty{
Description: paramConfig.Description,
Type: paramConfig.Type,
}
if paramConfig.Required {
swaggerInfo.Definitions[parentPath].Required = append(swaggerInfo.Definitions[parentPath].Required, paramConfig.Name)
}
}
return
}
if len(parentPath) == 0 {
parentPath = uri + ".input"
}
if len(subPathArr) == 2 {
if subPathArr[1] == "[]" {
swaggerInfo.Definitions[parentPath].Properties[subPathArr[0]] = &define.SwaggerDefinitionProperty{
Description: paramConfig.Description,
Type: "Array",
}
} else {
generateParameterDefinitions(swaggerInfo, uri, parentPath+"."+subPathArr[0], strings.Join(subPathArr[1:], "."), paramConfig)
}
return
}
generateParameterDefinitions(swaggerInfo, uri, parentPath+"."+subPathArr[0], strings.Join(subPathArr[1:], "."), paramConfig)
}
// generateResponseDefinitions ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:28 2024/4/22
func generateResponseDefinitions(swaggerInfo *define.Swagger, uri string, parentPath string, subPath string, responseConfig *define.SwaggerResponseItemInput) {
if nil == swaggerInfo.Definitions {
swaggerInfo.Definitions = map[string]*define.SwaggerDefinition{}
}
subPathArr := strings.Split(subPath, ".")
if _, exist := swaggerInfo.Definitions[parentPath]; !exist && len(parentPath) > 0 {
swaggerInfo.Definitions[parentPath] = &define.SwaggerDefinition{
Type: "object",
Required: make([]string, 0),
Properties: make(map[string]*define.SwaggerDefinitionProperty),
}
}
if len(subPathArr) == 1 {
if len(parentPath) == 0 {
return
}
swaggerInfo.Definitions[parentPath].Type = responseConfig.Type
/*swaggerInfo.Definitions[parentPath].Properties[paramConfig.Name] = &define.SwaggerDefinitionProperty{
Description: paramConfig.Description,
Type: paramConfig.Type,
}*/
return
}
if len(parentPath) == 0 {
parentPath = uri + ".output"
}
if len(subPathArr) == 2 {
if subPathArr[1] == "[]" {
swaggerInfo.Definitions[parentPath].Properties[subPathArr[0]] = &define.SwaggerDefinitionProperty{
Description: responseConfig.Description,
Type: "Array",
}
} else {
generateResponseDefinitions(swaggerInfo, uri, parentPath+"."+subPathArr[0], strings.Join(subPathArr[1:], "."), responseConfig)
}
return
}
generateResponseDefinitions(swaggerInfo, uri, parentPath+"."+subPathArr[0], strings.Join(subPathArr[1:], "."), responseConfig)
}
func getUri(uri string) string {
return "/" + strings.TrimLeft(uri, "/")
}