优化schema生成
This commit is contained in:
parent
27f2ccf2aa
commit
e4e8702fd4
@ -44,6 +44,7 @@ type PathConfig struct {
|
|||||||
Head *PathItemOperationConfig `json:"head,omitempty"` // 定义适用于此路径的 HEAD 操作。
|
Head *PathItemOperationConfig `json:"head,omitempty"` // 定义适用于此路径的 HEAD 操作。
|
||||||
Patch *PathItemOperationConfig `json:"patch,omitempty"` // 定义适用于此路径的 PATCH 操作。
|
Patch *PathItemOperationConfig `json:"patch,omitempty"` // 定义适用于此路径的 PATCH 操作。
|
||||||
Trace *PathItemOperationConfig `json:"trace,omitempty"` // 定义适用于此路径的 TRACE 操作。
|
Trace *PathItemOperationConfig `json:"trace,omitempty"` // 定义适用于此路径的 TRACE 操作。
|
||||||
|
Connect *PathItemOperationConfig `json:"connect,omitempty"` // 定义适用于此路径的 CONNECT 操作。
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathItemConfig 接口的具体配置
|
// PathItemConfig 接口的具体配置
|
||||||
@ -130,6 +131,7 @@ type Schema struct {
|
|||||||
Required []string `json:"required,omitempty"` // 必传属性列表
|
Required []string `json:"required,omitempty"` // 必传属性列表
|
||||||
Enum []any `json:"enum,omitempty"` // 枚举值列表
|
Enum []any `json:"enum,omitempty"` // 枚举值列表
|
||||||
Type string `json:"type"` // 类型
|
Type string `json:"type"` // 类型
|
||||||
|
Ref string `json:"$ref"` // 类型引用
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property 是从 JSON Schema 提取出来的,但是做了一些调整以适应 OpenAPI Specification。
|
// Property 是从 JSON Schema 提取出来的,但是做了一些调整以适应 OpenAPI Specification。
|
||||||
|
122
generate.go
122
generate.go
@ -8,9 +8,12 @@
|
|||||||
package api_doc
|
package api_doc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.zhangdeman.cn/gateway/api-doc/define"
|
"git.zhangdeman.cn/gateway/api-doc/define"
|
||||||
"git.zhangdeman.cn/zhangdeman/consts"
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -164,23 +167,96 @@ func (g *Generate) AddApi(baseCfg *define.UriBaseConfig, paramList []*define.Par
|
|||||||
return nil
|
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
|
// AddComponentsSchema 添加schema
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 15:25 2025/2/8
|
// Date : 15:25 2025/2/8
|
||||||
func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) string {
|
||||||
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)
|
|
||||||
}
|
|
||||||
if len(pkgPath) == 0 {
|
if len(pkgPath) == 0 {
|
||||||
pkgPath = inputType.PkgPath()
|
pkgPath = inputType.PkgPath()
|
||||||
}
|
}
|
||||||
@ -191,19 +267,20 @@ func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
|||||||
if inputType.Kind() == reflect.Ptr {
|
if inputType.Kind() == reflect.Ptr {
|
||||||
inputType = inputType.Elem()
|
inputType = inputType.Elem()
|
||||||
}
|
}
|
||||||
|
schemaName := schemaPrefix + inputType.Name()
|
||||||
if inputType.Kind() == reflect.Map {
|
if inputType.Kind() == reflect.Map {
|
||||||
// map, 直接添加公共
|
// map, 直接添加公共
|
||||||
if _, exist := g.docData.Components.Schemas[schemaPrefix+inputType.Name()]; !exist {
|
if _, exist := g.docData.Components.Schemas[schemaName]; !exist {
|
||||||
g.docData.Components.Schemas[schemaPrefix+inputType.Name()] = &define.Schema{
|
g.docData.Components.Schemas[schemaName] = &define.Schema{
|
||||||
Type: consts.SwaggerDataTypeObject,
|
Type: consts.SwaggerDataTypeObject,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return schemaName
|
||||||
}
|
}
|
||||||
// 数组
|
// 数组
|
||||||
if inputType.Kind() == reflect.Slice || inputType.Kind() == reflect.Array {
|
if inputType.Kind() == reflect.Slice || inputType.Kind() == reflect.Array {
|
||||||
g.parseSliceItem(inputType)
|
g.parseSliceItem(inputType)
|
||||||
return
|
return schemaName
|
||||||
}
|
}
|
||||||
// 结构体
|
// 结构体
|
||||||
if inputType.Kind() == reflect.Struct {
|
if inputType.Kind() == reflect.Struct {
|
||||||
@ -218,6 +295,7 @@ func (g *Generate) AddComponentsSchema(pkgPath string, inputType reflect.Type) {
|
|||||||
fmt.Println(inputType.Field(i).Name)
|
fmt.Println(inputType.Field(i).Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return schemaName
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSliceItem 解析数组每一项
|
// parseSliceItem 解析数组每一项
|
||||||
@ -238,3 +316,15 @@ func (g *Generate) parseSliceItem(inputType reflect.Type) string {
|
|||||||
}
|
}
|
||||||
return sliceItemType.PkgPath() + "." + sliceItemType.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
|
package api_doc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.zhangdeman.cn/gateway/api-doc/define"
|
"git.zhangdeman.cn/gateway/api-doc/define"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
"os"
|
"net/http"
|
||||||
"os/user"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -31,17 +29,19 @@ func Test_parser_Openapi3(t *testing.T) {
|
|||||||
List []A `json:"list"`
|
List []A `json:"list"`
|
||||||
}
|
}
|
||||||
var bArr []*B
|
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)))
|
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) {
|
func TestParseForSwagger(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user