// Package api_doc ... // // Description : api_doc ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2024-12-24 10:34 package api_doc import ( "errors" "git.zhangdeman.cn/gateway/api-doc/define" "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/serialize" "net/http" "strings" ) // ParseSwagger2 解析swagger2.0版本文档 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:33 2024/12/24 func ParseSwagger2(docContent []byte) (*define.DocParseResult, error) { var ( err error swaggerDoc define.Swagger ) if err = serialize.JSON.UnmarshalWithNumber(docContent, &swaggerDoc); nil != err { return nil, errors.New("parse swagger json fail : " + err.Error()) } docResult := &define.DocParseResult{ Domain: swaggerDoc.Host, Title: swaggerDoc.Info.Title, Description: swaggerDoc.Info.Description, UriList: make([]*define.UriBaseConfig, 0), GlobalSecurityParamList: make([]*define.ParamConfig, 0), } if docResult.UriList, err = buildUriList(&swaggerDoc); nil != err { return nil, err } docResult.GlobalSecurityParamList = buildSwagger2GlobalSecurityParamList(&swaggerDoc) return docResult, nil } // buildSwagger2GlobalSecurityParamList 构建全局安全类参数 func buildSwagger2GlobalSecurityParamList(swaggerDoc *define.Swagger) []*define.ParamConfig { result := make([]*define.ParamConfig, 0) for paramName, paramConfig := range swaggerDoc.SecurityDefinitions { if len(paramConfig.In) == 0 { continue } result = append(result, &define.ParamConfig{ Location: GetParamLocation(paramConfig.In).String(), Path: paramName, Type: GetDataType(paramConfig.Type, ""), Title: paramName, Description: paramConfig.Description, Required: false, }) } return result } // 解析uri列表 func buildUriList(swaggerDoc *define.Swagger) ([]*define.UriBaseConfig, error) { uriList := make([]*define.UriBaseConfig, 0) for itemUri, itemUriMethodConfig := range swaggerDoc.Paths { for requestMethod, methodConfig := range itemUriMethodConfig { initSwagger2UriMethodConfig(requestMethod, methodConfig) uriResult := &define.UriBaseConfig{ Uri: swaggerDoc.BasePath + "/" + strings.TrimLeft(itemUri, "/"), Method: strings.ToUpper(requestMethod), ContentType: methodConfig.Consumes, OutputContentType: methodConfig.Produces, TagList: methodConfig.Tags, Summary: methodConfig.Summary, Description: methodConfig.Description, ParamList: buildSwagger2ParamConfig(swaggerDoc, methodConfig.Parameters), ResultList: buildSwagger2ResultConfig(swaggerDoc, methodConfig.Responses), } uriList = append(uriList, uriResult) } } return uriList, nil } // 初始化配置请求方法 返回类型 func initSwagger2UriMethodConfig(requestMethod string, methodConfig *define.SwaggerPathConfig) { if len(methodConfig.Consumes) == 0 { // 未配置请求方法, 写请求 json , 读请求 form if strings.ToUpper(requestMethod) == http.MethodPost || strings.ToUpper(requestMethod) == http.MethodPut || strings.ToUpper(requestMethod) == http.MethodPatch || strings.ToUpper(requestMethod) == http.MethodDelete { methodConfig.Consumes = []string{ consts.MimeTypeJson, } } else { methodConfig.Consumes = []string{ consts.MimeTypeXWWWFormUrlencoded, } } } if len(methodConfig.Produces) == 0 { // 未配置输出数据类型, 默认 json methodConfig.Produces = []string{ consts.MimeTypeJson, } } } // buildSwagger2ParamConfig 构建请求参数配置 func buildSwagger2ParamConfig(swaggerDoc *define.Swagger, paramConfigList []*define.SwaggerPathConfigParameter) []*define.ParamConfig { res := make([]*define.ParamConfig, 0) // 解析参数 for _, paramConfig := range paramConfigList { if paramConfig.Name != "body" { paramConfigBuildConfig := &define.ParamConfig{ Location: GetParamLocation(paramConfig.In).String(), Path: paramConfig.Name, Type: GetDataType(paramConfig.Type, paramConfig.Format), Title: paramConfig.Name, Description: paramConfig.Description, Required: paramConfig.Required, } res = append(res, paramConfigBuildConfig) } if nil == paramConfig.Schema || len(paramConfig.Schema.Ref) == 0 { continue } // 可以继续展开 requiredTable := make(map[string]bool) for _, paramName := range swaggerDoc.Definitions[GetRealDefinitionsKey(paramConfig.Schema.Ref)].Required { requiredTable[paramName] = true } for paramName, paramMoreConfig := range swaggerDoc.Definitions[GetRealDefinitionsKey(paramConfig.Schema.Ref)].Properties { if paramConfig.Name != "body" { paramName = paramConfig.Name + "." + paramName } paramConfigBuildConfig := &define.ParamConfig{ Location: GetParamLocation(paramConfig.In).String(), Path: paramName, Type: GetDataType(paramMoreConfig.Type, ""), Title: paramName, Description: paramMoreConfig.Description, Required: requiredTable[paramName], } res = append(res, paramConfigBuildConfig) if DataTypeIsArray(paramMoreConfig.Type) && nil != paramMoreConfig.Items && len(paramMoreConfig.Items.Ref) > 0 { // 是数组,且每一项是对象, 继续展开 res = append(res, ExpandArrayParam(swaggerDoc, paramMoreConfig.Items.Ref, paramConfigBuildConfig.Path)...) } } } return res } // buildSwagger2ResultConfig 构建响应结果配置 func buildSwagger2ResultConfig(swaggerDoc *define.Swagger, resultConfig map[string]*define.SwaggerPathConfigResponse) []*define.ResultConfig { res := make([]*define.ResultConfig, 0) if nil == resultConfig || len(resultConfig) == 0 { return res } successResponseConfig := GetSuccessResponseConfig(resultConfig) if nil == successResponseConfig { return res } definitionsKey := "" if swaggerDoc.Responses == nil { definitionsKey = successResponseConfig.Schema.Ref } else { responseKey := GetRealResponseKey(successResponseConfig.Ref) if len(responseKey) == 0 { // 204 场景下,可能没有响应body res = append(res, &define.ResultConfig{ Location: consts.ResponseDataLocationBody.String(), Path: consts.ResponseDataLocationBodyRoot.String(), Type: consts.DataTypeAny.String(), Title: "response body no content", Description: "no content", }) return res } ref := swaggerDoc.Responses[responseKey].Ref if len(ref) == 0 { if nil != swaggerDoc.Responses[responseKey].Schema { ref = swaggerDoc.Responses[responseKey].Schema.Ref } } definitionsKey = GetRealDefinitionsKey(ref) } if len(definitionsKey) == 0 { // 不是引用类型, 直接定义的具体类型 responseKey := GetRealResponseKey(successResponseConfig.Ref) responseTypeDefine := swaggerDoc.Responses[responseKey] responseType := "" schemaType := "" if nil == responseTypeDefine.Schema { // 204 等场景下,可能没有响应body responseType = consts.DataTypeAny.String() } else { schemaType = responseTypeDefine.Schema.Type responseType = GetDataType(responseTypeDefine.Schema.Type, "") } resCfg := &define.ResultConfig{ Location: consts.ResponseDataLocationBody.String(), Path: consts.ResponseDataLocationBodyRoot.String(), Type: responseType, Title: "response body", Description: "response body", } res = append(res, resCfg) if DataTypeIsArray(schemaType) && len(responseTypeDefine.Schema.Items.Ref) > 0 { res = append(res, ExpandArrayResult(swaggerDoc, responseTypeDefine.Schema.Items.Ref, resCfg.Path)...) } } else { responseTypeDefine := swaggerDoc.Definitions[definitionsKey] for responseKey, responseKeyConfig := range responseTypeDefine.Properties { res = append(res, &define.ResultConfig{ Location: consts.ResponseDataLocationBody.String(), Path: responseKey, Type: GetDataType(responseKeyConfig.Type, ""), Title: responseKey, Description: responseKey, }) } } return res }