234 lines
8.0 KiB
Go
234 lines
8.0 KiB
Go
// 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, "").String(),
|
||
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[0],
|
||
OutputContentType: methodConfig.Produces[0],
|
||
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).String(),
|
||
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, "").String(),
|
||
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, "").String()
|
||
}
|
||
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, "").String(),
|
||
Title: responseKey,
|
||
Description: responseKey,
|
||
})
|
||
}
|
||
}
|
||
return res
|
||
}
|