feat: 完成基础文档生成
This commit is contained in:
@@ -8,9 +8,14 @@
|
|||||||
package openapi
|
package openapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.zhangdeman.cn/zhangdeman/api-doc/define"
|
||||||
"git.zhangdeman.cn/zhangdeman/consts"
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper/op_array"
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
"github.com/getkin/kin-openapi/openapi3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,12 +96,12 @@ func NewGenerate() *Generate {
|
|||||||
Security: []openapi3.SecurityRequirement{},
|
Security: []openapi3.SecurityRequirement{},
|
||||||
Servers: []*openapi3.Server{},
|
Servers: []*openapi3.Server{},
|
||||||
Tags: []*openapi3.Tag{},
|
Tags: []*openapi3.Tag{},
|
||||||
ExternalDocs: &openapi3.ExternalDocs{
|
/*ExternalDocs: &openapi3.ExternalDocs{
|
||||||
Extensions: map[string]any{},
|
Extensions: map[string]any{},
|
||||||
Origin: nil,
|
Origin: nil,
|
||||||
Description: "",
|
Description: "",
|
||||||
URL: "",
|
URL: "",
|
||||||
},
|
},*/
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +112,7 @@ type Generate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddApiDoc 添加接口文档
|
// AddApiDoc 添加接口文档
|
||||||
func (g *Generate) AddApiDoc(request any, response any) error {
|
func (g *Generate) AddApiDoc(apiMeta define.UriConfig, request any, response any) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
requestType reflect.Type
|
requestType reflect.Type
|
||||||
@@ -129,13 +134,130 @@ func (g *Generate) AddApiDoc(request any, response any) error {
|
|||||||
responseType = responseType.Elem()
|
responseType = responseType.Elem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestTypeStr := requestType.String()
|
|
||||||
if _, exist := g.doc.Components.Schemas[requestTypeStr]; !exist {
|
schemaData := GenerateOpenAPISchema(requestType)
|
||||||
g.doc.Components.Schemas[requestTypeStr] = GenerateOpenAPISchema(requestType)
|
apiOperate, isRead := g.initApiConfig(apiMeta)
|
||||||
|
requestTypeStr := strings.ReplaceAll(requestType.String(), ".", "_")
|
||||||
|
if isRead {
|
||||||
|
for paramName, paramConfig := range schemaData.Value.Properties {
|
||||||
|
apiOperate.Parameters = append(apiOperate.Parameters, &openapi3.ParameterRef{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Ref: "",
|
||||||
|
Value: &openapi3.Parameter{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Name: paramName,
|
||||||
|
In: strings.ToLower(consts.RequestDataLocationQuery.String()),
|
||||||
|
Description: paramConfig.Value.Description,
|
||||||
|
Style: "",
|
||||||
|
Explode: nil,
|
||||||
|
AllowEmptyValue: false,
|
||||||
|
AllowReserved: false,
|
||||||
|
Deprecated: false,
|
||||||
|
Required: op_array.ArrayType(paramConfig.Value.Required).Has(paramName) >= 0,
|
||||||
|
Schema: paramConfig,
|
||||||
|
Example: nil,
|
||||||
|
Examples: nil,
|
||||||
|
Content: nil,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apiOperate.RequestBody = &openapi3.RequestBodyRef{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Ref: requestTypeStr,
|
||||||
|
Value: nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
responseTypeStr := requestType.String()
|
|
||||||
|
// 初始化接口配置
|
||||||
|
if _, exist := g.doc.Components.Schemas[requestTypeStr]; !exist {
|
||||||
|
g.doc.Components.Schemas[requestTypeStr] = schemaData
|
||||||
|
}
|
||||||
|
responseTypeStr := strings.ReplaceAll(requestType.String(), ".", "_")
|
||||||
if _, exist := g.doc.Components.Schemas[responseTypeStr]; !exist {
|
if _, exist := g.doc.Components.Schemas[responseTypeStr]; !exist {
|
||||||
g.doc.Components.Schemas[responseTypeStr] = GenerateOpenAPISchema(responseType)
|
g.doc.Components.Schemas[responseTypeStr] = GenerateOpenAPISchema(responseType)
|
||||||
}
|
}
|
||||||
|
desc := "请求成功"
|
||||||
|
apiOperate.Responses.Set(fmt.Sprintf("%v", http.StatusOK), &openapi3.ResponseRef{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Ref: "",
|
||||||
|
Value: &openapi3.Response{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Description: &desc,
|
||||||
|
Headers: nil,
|
||||||
|
Content: map[string]*openapi3.MediaType{
|
||||||
|
consts.MimeTypeJson: {
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Schema: g.doc.Components.Schemas[responseTypeStr],
|
||||||
|
Example: nil,
|
||||||
|
Examples: nil,
|
||||||
|
Encoding: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Links: nil,
|
||||||
|
},
|
||||||
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initApiConfig 初始化接口配置, 并返回 operation 以及 是否读请求
|
||||||
|
func (g *Generate) initApiConfig(apiMeta define.UriConfig) (*openapi3.Operation, bool) {
|
||||||
|
if nil == g.doc.Paths.Value(apiMeta.Path) {
|
||||||
|
g.doc.Paths.Set(apiMeta.Path, &openapi3.PathItem{
|
||||||
|
Extensions: nil,
|
||||||
|
Origin: nil,
|
||||||
|
Ref: "",
|
||||||
|
Summary: "",
|
||||||
|
Description: "",
|
||||||
|
Connect: nil,
|
||||||
|
Delete: nil,
|
||||||
|
Get: nil,
|
||||||
|
Head: nil,
|
||||||
|
Options: nil,
|
||||||
|
Patch: nil,
|
||||||
|
Post: nil,
|
||||||
|
Put: nil,
|
||||||
|
Trace: nil,
|
||||||
|
Servers: nil,
|
||||||
|
Parameters: nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
newOperate := openapi3.NewOperation()
|
||||||
|
newOperate.Parameters = make(openapi3.Parameters, 0)
|
||||||
|
newOperate.Responses = openapi3.NewResponses()
|
||||||
|
isRead := false
|
||||||
|
switch apiMeta.RequestMethod {
|
||||||
|
case http.MethodGet:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Get = newOperate
|
||||||
|
isRead = true
|
||||||
|
case http.MethodHead:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Head = newOperate
|
||||||
|
isRead = true
|
||||||
|
case http.MethodConnect:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Connect = newOperate
|
||||||
|
isRead = true
|
||||||
|
case http.MethodOptions:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Options = newOperate
|
||||||
|
isRead = true
|
||||||
|
case http.MethodTrace:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Trace = newOperate
|
||||||
|
isRead = true
|
||||||
|
// 读请求
|
||||||
|
case http.MethodPost:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Post = newOperate
|
||||||
|
case http.MethodPut:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Put = newOperate
|
||||||
|
case http.MethodPatch:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Patch = newOperate
|
||||||
|
case http.MethodDelete:
|
||||||
|
g.doc.Paths.Value(apiMeta.Path).Delete = newOperate
|
||||||
|
// 写请求
|
||||||
|
}
|
||||||
|
return newOperate, isRead
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ package openapi
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.zhangdeman.cn/zhangdeman/api-doc/define"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerate_AddApiDoc(t *testing.T) {
|
func TestGenerate_AddApiDoc(t *testing.T) {
|
||||||
@@ -20,7 +23,7 @@ func TestGenerate_AddApiDoc(t *testing.T) {
|
|||||||
Name string `json:"name" description:"分类名称"`
|
Name string `json:"name" description:"分类名称"`
|
||||||
}
|
}
|
||||||
type Product struct {
|
type Product struct {
|
||||||
ID int64 `json:"id" description:"产品ID" example:"1001" required:"true"`
|
ID int64 `json:"id,omitempty" description:"产品ID" example:"1001" required:"true" binding:"required"`
|
||||||
Name string `json:"name" description:"产品名称" example:"iPhone 13" minLength:"2" maxLength:"100" required:"true"`
|
Name string `json:"name" description:"产品名称" example:"iPhone 13" minLength:"2" maxLength:"100" required:"true"`
|
||||||
Price float64 `json:"price" description:"价格" example:"6999.99" min:"0"`
|
Price float64 `json:"price" description:"价格" example:"6999.99" min:"0"`
|
||||||
Stock int `json:"stock" description:"库存" example:"100" min:"0"`
|
Stock int `json:"stock" description:"库存" example:"100" min:"0"`
|
||||||
@@ -31,7 +34,12 @@ func TestGenerate_AddApiDoc(t *testing.T) {
|
|||||||
Category *Category `json:"category,omitempty" description:"分类"`
|
Category *Category `json:"category,omitempty" description:"分类"`
|
||||||
}
|
}
|
||||||
instance := NewGenerate()
|
instance := NewGenerate()
|
||||||
instance.AddApiDoc(Category{}, Product{})
|
instance.AddApiDoc(define.UriConfig{
|
||||||
|
Path: "/a/b/c",
|
||||||
|
RequestMethod: http.MethodGet,
|
||||||
|
TagList: []string{"test"},
|
||||||
|
Desc: "测试接口",
|
||||||
|
}, Category{}, Product{})
|
||||||
// 输出 JSON
|
// 输出 JSON
|
||||||
data, _ := json.MarshalIndent(instance.doc, "", " ")
|
data, _ := json.MarshalIndent(instance.doc, "", " ")
|
||||||
fmt.Println(string(data))
|
fmt.Println(string(data))
|
||||||
|
|||||||
Reference in New Issue
Block a user