api-doc/swagger.go

234 lines
8.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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
}