优化schema生成
This commit is contained in:
parent
27f2ccf2aa
commit
e4e8702fd4
@ -44,6 +44,7 @@ type PathConfig struct {
|
||||
Head *PathItemOperationConfig `json:"head,omitempty"` // 定义适用于此路径的 HEAD 操作。
|
||||
Patch *PathItemOperationConfig `json:"patch,omitempty"` // 定义适用于此路径的 PATCH 操作。
|
||||
Trace *PathItemOperationConfig `json:"trace,omitempty"` // 定义适用于此路径的 TRACE 操作。
|
||||
Connect *PathItemOperationConfig `json:"connect,omitempty"` // 定义适用于此路径的 CONNECT 操作。
|
||||
}
|
||||
|
||||
// PathItemConfig 接口的具体配置
|
||||
@ -130,6 +131,7 @@ type Schema struct {
|
||||
Required []string `json:"required,omitempty"` // 必传属性列表
|
||||
Enum []any `json:"enum,omitempty"` // 枚举值列表
|
||||
Type string `json:"type"` // 类型
|
||||
Ref string `json:"$ref"` // 类型引用
|
||||
}
|
||||
|
||||
// Property 是从 JSON Schema 提取出来的,但是做了一些调整以适应 OpenAPI Specification。
|
||||
|
122
generate.go
122
generate.go
@ -8,9 +8,12 @@
|
||||
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"
|
||||
)
|
||||
@ -164,23 +167,96 @@ func (g *Generate) AddApi(baseCfg *define.UriBaseConfig, paramList []*define.Par
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddApiFromInAndOut 通过请求参数的
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:22 2025/2/9
|
||||
func (g *Generate) AddApiFromInAndOut(baseCfg *define.UriBaseConfig, paramType reflect.Type, resultType reflect.Type) error {
|
||||
if nil == baseCfg {
|
||||
return errors.New("baseCfg is nil")
|
||||
}
|
||||
if baseCfg.Method == "" {
|
||||
return errors.New("baseCfg.Method is empty")
|
||||
}
|
||||
if baseCfg.Uri == "" {
|
||||
return errors.New("baseCfg.Uri is empty")
|
||||
}
|
||||
baseCfg.Method = strings.ToUpper(baseCfg.Method)
|
||||
paramMethod := []string{
|
||||
http.MethodGet, http.MethodHead, http.MethodConnect, http.MethodOptions, http.MethodTrace,
|
||||
}
|
||||
if wrapper.ArrayType(paramMethod).Has(baseCfg.Method) >= 0 {
|
||||
// Get类请求, TODO : get类解析
|
||||
return nil
|
||||
}
|
||||
// post类解析
|
||||
defaultPkgPath := wrapper.String(strings.ReplaceAll(strings.TrimLeft(baseCfg.Uri, "/"), "/", "_")).SnakeCaseToCamel()
|
||||
paramPkgPath := defaultPkgPath + "Param"
|
||||
resultPkgPath := defaultPkgPath + "Result"
|
||||
g.AddComponentsSchema(paramPkgPath, paramType)
|
||||
g.AddComponentsSchema(resultPkgPath, resultType)
|
||||
if _, exist := g.docData.Paths[baseCfg.Uri]; !exist {
|
||||
g.docData.Paths[baseCfg.Uri] = &define.PathConfig{}
|
||||
}
|
||||
cfg := &define.PathItemOperationConfig{
|
||||
Tags: baseCfg.TagList,
|
||||
Summary: baseCfg.Summary,
|
||||
Description: baseCfg.Description,
|
||||
ExternalDocs: nil,
|
||||
OperationID: defaultPkgPath + baseCfg.Method,
|
||||
Parameters: nil,
|
||||
RequestBody: &define.RequestBody{
|
||||
Required: true,
|
||||
Description: "",
|
||||
Content: map[string]*define.Media{},
|
||||
Ref: "",
|
||||
},
|
||||
Responses: nil,
|
||||
Callbacks: nil,
|
||||
Deprecated: false,
|
||||
Security: nil,
|
||||
Servers: nil,
|
||||
}
|
||||
for _, itemOutputType := range baseCfg.OutputContentType {
|
||||
cfg.RequestBody.Content[itemOutputType] = &define.Media{
|
||||
Schema: &define.Schema{
|
||||
Ref: g.getSchemaRes(paramPkgPath + "." + paramType.Name()),
|
||||
},
|
||||
Example: "",
|
||||
Examples: nil,
|
||||
Encoding: nil,
|
||||
}
|
||||
}
|
||||
switch baseCfg.Method {
|
||||
case http.MethodGet:
|
||||
g.docData.Paths[baseCfg.Uri].Get = cfg
|
||||
case http.MethodHead:
|
||||
g.docData.Paths[baseCfg.Uri].Head = cfg
|
||||
case http.MethodPost:
|
||||
g.docData.Paths[baseCfg.Uri].Post = cfg
|
||||
case http.MethodPut:
|
||||
g.docData.Paths[baseCfg.Uri].Put = cfg
|
||||
case http.MethodPatch:
|
||||
g.docData.Paths[baseCfg.Uri].Patch = cfg
|
||||
case http.MethodDelete:
|
||||
g.docData.Paths[baseCfg.Uri].Delete = cfg
|
||||
case http.MethodConnect:
|
||||
g.docData.Paths[baseCfg.Uri].Connect = cfg
|
||||
case http.MethodOptions:
|
||||
g.docData.Paths[baseCfg.Uri].Options = cfg
|
||||
case http.MethodTrace:
|
||||
g.docData.Paths[baseCfg.Uri].Trace = cfg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddComponentsSchema 添加schema
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:25 2025/2/8
|
||||
func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
||||
if nil == g.docData {
|
||||
g.docData = &define.OpenapiDoc{}
|
||||
}
|
||||
if nil == g.docData.Components {
|
||||
g.docData.Components = &define.Components{
|
||||
Schemas: map[string]*define.Schema{},
|
||||
}
|
||||
}
|
||||
if nil == g.docData.Components.Schemas {
|
||||
g.docData.Components.Schemas = make(map[string]*define.Schema)
|
||||
}
|
||||
func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) string {
|
||||
if len(pkgPath) == 0 {
|
||||
pkgPath = inputType.PkgPath()
|
||||
}
|
||||
@ -191,19 +267,20 @@ func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
||||
if inputType.Kind() == reflect.Ptr {
|
||||
inputType = inputType.Elem()
|
||||
}
|
||||
schemaName := schemaPrefix + inputType.Name()
|
||||
if inputType.Kind() == reflect.Map {
|
||||
// map, 直接添加公共
|
||||
if _, exist := g.docData.Components.Schemas[schemaPrefix+inputType.Name()]; !exist {
|
||||
g.docData.Components.Schemas[schemaPrefix+inputType.Name()] = &define.Schema{
|
||||
if _, exist := g.docData.Components.Schemas[schemaName]; !exist {
|
||||
g.docData.Components.Schemas[schemaName] = &define.Schema{
|
||||
Type: consts.SwaggerDataTypeObject,
|
||||
}
|
||||
}
|
||||
return
|
||||
return schemaName
|
||||
}
|
||||
// 数组
|
||||
if inputType.Kind() == reflect.Slice || inputType.Kind() == reflect.Array {
|
||||
g.parseSliceItem(inputType)
|
||||
return
|
||||
return schemaName
|
||||
}
|
||||
// 结构体
|
||||
if inputType.Kind() == reflect.Struct {
|
||||
@ -218,6 +295,7 @@ func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
||||
fmt.Println(inputType.Field(i).Name)
|
||||
}
|
||||
}
|
||||
return schemaName
|
||||
}
|
||||
|
||||
// parseSliceItem 解析数组每一项
|
||||
@ -238,3 +316,15 @@ func (g *Generate) parseSliceItem(inputType reflect.Type) string {
|
||||
}
|
||||
return sliceItemType.PkgPath() + "." + sliceItemType.String()
|
||||
}
|
||||
|
||||
// getSchemaRes 获取引用的类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:25 2025/2/9
|
||||
func (g *Generate) getSchemaRes(schemaName string) string {
|
||||
if "" == schemaName {
|
||||
return ""
|
||||
}
|
||||
return "#/components/schemas/" + schemaName
|
||||
}
|
||||
|
@ -8,12 +8,10 @@
|
||||
package api_doc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/gateway/api-doc/define"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"os"
|
||||
"os/user"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
@ -31,17 +29,19 @@ func Test_parser_Openapi3(t *testing.T) {
|
||||
List []A `json:"list"`
|
||||
}
|
||||
var bArr []*B
|
||||
g := Generate{}
|
||||
g := NewOpenapiDoc()
|
||||
g.AddApiFromInAndOut(&define.UriBaseConfig{
|
||||
Uri: "/a/b/c/d",
|
||||
Method: http.MethodPost,
|
||||
ContentType: []string{"application/x-www-form-urlencoded"},
|
||||
OutputContentType: []string{"application/yml", "application/json", "application/xml"},
|
||||
TagList: []string{"测试文档生成"},
|
||||
Summary: "测试接口",
|
||||
Description: "",
|
||||
ParamList: nil,
|
||||
ResultList: nil,
|
||||
}, reflect.TypeOf(bArr), reflect.TypeOf(bArr))
|
||||
fmt.Println(g.parseSliceItem(reflect.TypeOf(bArr)))
|
||||
current, _ := user.Current()
|
||||
byteData, _ := os.ReadFile(current.HomeDir + "/Downloads/test-openapi-doc.json")
|
||||
var data define.OpenapiDoc
|
||||
err := json.Unmarshal(byteData, &data)
|
||||
if nil != err {
|
||||
fmt.Println("解析失败 : " + err.Error())
|
||||
} else {
|
||||
fmt.Println("解析成功")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseForSwagger(t *testing.T) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user