From 0dd0e8f22f979b69c9b22d5f639fd3951f1cd8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Tue, 6 Jan 2026 18:05:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi/generate.go | 136 +++++++++++++++++++++++++++++++++++++-- openapi/generate_test.go | 12 +++- 2 files changed, 139 insertions(+), 9 deletions(-) diff --git a/openapi/generate.go b/openapi/generate.go index 1ac9de1..920349e 100644 --- a/openapi/generate.go +++ b/openapi/generate.go @@ -8,9 +8,14 @@ package openapi import ( + "fmt" + "net/http" "reflect" + "strings" + "git.zhangdeman.cn/zhangdeman/api-doc/define" "git.zhangdeman.cn/zhangdeman/consts" + "git.zhangdeman.cn/zhangdeman/wrapper/op_array" "github.com/getkin/kin-openapi/openapi3" ) @@ -91,12 +96,12 @@ func NewGenerate() *Generate { Security: []openapi3.SecurityRequirement{}, Servers: []*openapi3.Server{}, Tags: []*openapi3.Tag{}, - ExternalDocs: &openapi3.ExternalDocs{ + /*ExternalDocs: &openapi3.ExternalDocs{ Extensions: map[string]any{}, Origin: nil, Description: "", URL: "", - }, + },*/ }, } } @@ -107,7 +112,7 @@ type Generate struct { } // AddApiDoc 添加接口文档 -func (g *Generate) AddApiDoc(request any, response any) error { +func (g *Generate) AddApiDoc(apiMeta define.UriConfig, request any, response any) error { var ( err error requestType reflect.Type @@ -129,13 +134,130 @@ func (g *Generate) AddApiDoc(request any, response any) error { responseType = responseType.Elem() } } - requestTypeStr := requestType.String() - if _, exist := g.doc.Components.Schemas[requestTypeStr]; !exist { - g.doc.Components.Schemas[requestTypeStr] = GenerateOpenAPISchema(requestType) + + schemaData := 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 { 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 } + +// 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 +} diff --git a/openapi/generate_test.go b/openapi/generate_test.go index 413fc7e..1f4ab87 100644 --- a/openapi/generate_test.go +++ b/openapi/generate_test.go @@ -10,8 +10,11 @@ package openapi import ( "encoding/json" "fmt" + "net/http" "testing" "time" + + "git.zhangdeman.cn/zhangdeman/api-doc/define" ) func TestGenerate_AddApiDoc(t *testing.T) { @@ -20,7 +23,7 @@ func TestGenerate_AddApiDoc(t *testing.T) { Name string `json:"name" description:"分类名称"` } 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"` Price float64 `json:"price" description:"价格" example:"6999.99" 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:"分类"` } instance := NewGenerate() - instance.AddApiDoc(Category{}, Product{}) + instance.AddApiDoc(define.UriConfig{ + Path: "/a/b/c", + RequestMethod: http.MethodGet, + TagList: []string{"test"}, + Desc: "测试接口", + }, Category{}, Product{}) // 输出 JSON data, _ := json.MarshalIndent(instance.doc, "", " ") fmt.Println(string(data))