From 8192b40c6e1744aaa1511823760fb2c6613396d1 Mon Sep 17 00:00:00 2001 From: alovn Date: Sat, 14 May 2022 13:44:54 +0800 Subject: [PATCH] feat: response time.Time, map type comment --- examples/docs/README.md | 8 +++-- examples/docs/apis-demo.md | 39 +++++++++++++++++++----- examples/docs/apis-profile.md | 2 +- examples/svc-greeter/main.go | 38 +++++++++++++++-------- examples/svc-user/handler/demo.go | 25 ++++++++++++++-- examples/svc-user/main.go | 1 + gen/template/group_readme.tpl | 5 ++++ gen/template/single.tpl | 5 ++++ operation.go | 2 +- parser.go | 50 ++++++++++++++++++------------- spec.go | 36 +++++++++++++++------- 11 files changed, 153 insertions(+), 58 deletions(-) diff --git a/examples/docs/README.md b/examples/docs/README.md index 9f8c230..8475939 100644 --- a/examples/docs/README.md +++ b/examples/docs/README.md @@ -1,5 +1,7 @@ # 用户服务 (svc-user) +version: _@1.0.1_ + 用户相关的服务接口 1. [账户相关](./apis-account.md) @@ -38,6 +40,8 @@ 5.4. [int](./apis-demo.md#4-int) - 5.5. [DemoMap](./apis-demo.md#5-DemoMap) + 5.5. [map](./apis-demo.md#5-map) + + 5.6. [xml](./apis-demo.md#6-xml) - 5.6. [XML测试](./apis-demo.md#6-XML测试) + 5.7. [time](./apis-demo.md#7-time) diff --git a/examples/docs/apis-demo.md b/examples/docs/apis-demo.md index 9637bba..3c48797 100644 --- a/examples/docs/apis-demo.md +++ b/examples/docs/apis-demo.md @@ -6,8 +6,9 @@ 2. [struct嵌套](#2-struct嵌套) 3. [int数组](#3-int数组) 4. [int](#4-int) -5. [DemoMap](#5-DemoMap) -6. [XML测试](#6-XML测试) +5. [map](#5-map) +6. [xml](#6-xml) +7. [time](#7-time) ## apis @@ -32,7 +33,7 @@ __Response__: 123 ], "int_pointer": 123, //int - "map": { //object(Map) + "map": { //object(map[string]int) "abc": 123 //int }, "object_1": { //object(handler.DemoObject) @@ -99,7 +100,7 @@ __Response__: --- -### 5. DemoMap +### 5. map ```text GET /user/demo/map @@ -109,7 +110,7 @@ __Response__: ```javascript //StatusCode: 200 demo map -{ //object(handler.DemoData) +{ //object(map[string]handler.DemoData) "abc": { //object(handler.DemoData) "count": 123, //int "description": "abc", //string @@ -120,7 +121,7 @@ __Response__: 123 ], "int_pointer": 123, //int - "map": { //object(Map) + "map": { //object(map[string]int) "abc": 123 //int }, "object_1": { //object(handler.DemoObject) @@ -136,7 +137,7 @@ __Response__: --- -### 6. XML测试 +### 6. xml author: _alovn_ @@ -195,3 +196,27 @@ __Response__: ``` --- + +### 7. time + +author: _alovn_ + +```text +GET /user/demo/time +``` + +__Response__: + +```javascript +//StatusCode: 200 +{ //object(common.Response), 通用返回结果 + "code": 0, //int, 返回状态码 + "data": { //object(handler.DemoTime) + "time_1": "2022-05-14T03:32:48.037644+08:00", //object(time.Time), example1 + "time_2": 2022-05-14 15:04:05 //object(time.Time), example2 + }, + "msg": "success" //string, 返回消息 +} +``` + +--- diff --git a/examples/docs/apis-profile.md b/examples/docs/apis-profile.md index 191a579..dc2c21a 100644 --- a/examples/docs/apis-profile.md +++ b/examples/docs/apis-profile.md @@ -21,7 +21,7 @@ __Response__: { //object(common.Response), 通用返回结果 "code": 0, //int, 返回状态码 "data": { //object(handler.ProfileResponse) - "extends": { //object(Extends) + "extends": { //object(map[string]string) "abc": "abc" //string, 扩展信息 }, "gender": 1, //uint8 diff --git a/examples/svc-greeter/main.go b/examples/svc-greeter/main.go index 607700b..debf4d6 100644 --- a/examples/svc-greeter/main.go +++ b/examples/svc-greeter/main.go @@ -3,6 +3,7 @@ package main import ( "encoding/xml" "fmt" + "time" "github.com/alovn/apidoc/examples/common" ) @@ -36,6 +37,7 @@ type TestData2 struct { } type Map map[string]interface{} type Map2 map[string]TestData2 +type Map3 map[string]string type Node struct { Name string Nodes map[string]Node @@ -47,15 +49,17 @@ type TestData struct { // MyFloat64 float64 // MyFloat32 float32 // MyIntArray []int - MyTestData2Array []TestData2 + MyTestData2Array []TestData2 `json:"my_test_data_2_array,omitempty"` // Int *int // MyInt MyInt - MyInts []MyInt - // Map Map `json:"amap"` - // Map2 Map2 + MyInts []MyInt `json:"my_ints,omitempty"` + // Map Map `json:"amap"` + // Map map[string]string + Map2 Map2 `json:"map_2,omitempty"` // Map3 map[string]TestData2 - Nodes map[string]Node - // Map4 map[int]Node + // Nodes map[string]Node + // Map4 map[int]Node + Time1 time.Time `xml:"time_1,omitempty"` } type Request struct { @@ -66,8 +70,9 @@ type Request struct { } //请求对象 type Struct1 struct { - Name string - Struct2 + Name string + Time1 time.Time + // Struct2 } type Struct2 struct { Name2 string @@ -93,17 +98,24 @@ type XMLData2 struct { Desc string } +type DemoTime struct { + // Title string //测试 + Map map[string]string //map测试 + // Time1 time.Time `xml:"time_1" json:"time_1"` //example1 + // Time2 time.Time `xml:"time_2" json:"time_2" example:"2022-05-14 15:04:05"` //example2 +} + //@title 测试greeter //@api GET /greeter //@group greeter //@accept xml -//@format xml -//@request Request +//@format json +//@request1 Request //@response1 200 TestData "输出对象" //@response1 200 Struct1 "struct1" -//@response 200 XMLResponse{data=[]XMLData} "输出xml" -//@response 200 XMLResponse{data=[]XMLData2} "输出xml2" -//@response1 200 common.Response{data=TestData} "输出对象 dd" +//@response1 200 XMLResponse{data=[]XMLData} "输出xml" +//@response1 200 XMLResponse{data=[]XMLData2} "输出xml2" +//@response 200 common.Response{data=DemoTime} "输出对象 dd" //@response1 500 Response{code=10010,msg="异常"} "出错了" //@response1 500 int 错误 func greet() { diff --git a/examples/svc-user/handler/demo.go b/examples/svc-user/handler/demo.go index 130ec43..934de1a 100644 --- a/examples/svc-user/handler/demo.go +++ b/examples/svc-user/handler/demo.go @@ -4,6 +4,7 @@ import ( "encoding/json" "encoding/xml" "net/http" + "time" "github.com/alovn/apidoc/examples/common" ) @@ -73,7 +74,7 @@ func (h *DemoHandler) Int(w http.ResponseWriter, r *http.Request) { } //@api GET /demo/map -//@title DemoMap +//@title map //@group demo //@response 200 DemoMap "demo map" func (h *DemoHandler) Map(w http.ResponseWriter, r *http.Request) { @@ -98,7 +99,7 @@ type DemoXMLResponse2 struct { } //XML测试返回对象2 //@api GET /demo/xml -//@title XML测试 +//@title xml //@group demo //@accept xml //@request DemoXMLRequest @@ -113,3 +114,23 @@ func (h *AddressHandler) XML(w http.ResponseWriter, r *http.Request) { b, _ := json.Marshal(res) _, _ = w.Write(b) } + +type DemoTime struct { + // Title string //测试 + Time1 time.Time `xml:"time_1" json:"time_1"` //example1 + Time2 time.Time `xml:"time_2" json:"time_2" example:"2022-05-14 15:04:05"` //example2 +} + +//@api GET /demo/time +//@title time +//@group demo +//@accept xml +//@format json +//@response 200 common.Response{code=0,msg="success",data=DemoTime} +//@author alovn +func (h *AddressHandler) Time(w http.ResponseWriter, r *http.Request) { + address := DemoXMLRequest{} + res := common.NewResponse(200, "获取成功", address) + b, _ := json.Marshal(res) + _, _ = w.Write(b) +} diff --git a/examples/svc-user/main.go b/examples/svc-user/main.go index 52c53de..0d0f10d 100644 --- a/examples/svc-user/main.go +++ b/examples/svc-user/main.go @@ -8,6 +8,7 @@ import ( //@title 用户服务 //@service svc-user +//@version 1.0.1 //@desc 用户相关的服务接口 //@baseurl /user func main() { diff --git a/gen/template/group_readme.tpl b/gen/template/group_readme.tpl index 4621663..dd64504 100644 --- a/gen/template/group_readme.tpl +++ b/gen/template/group_readme.tpl @@ -1,5 +1,10 @@ # {{.Title}} {{if .Service}} ({{.Service}}){{end}} +{{- if .Version}} + +version: _@{{.Version}}_ +{{- end}} + {{- if .Description}} {{.Description}} diff --git a/gen/template/single.tpl b/gen/template/single.tpl index 96909bc..8a6966c 100644 --- a/gen/template/single.tpl +++ b/gen/template/single.tpl @@ -1,5 +1,10 @@ # {{.Title}} {{if .Service}} ({{.Service}}){{end}} +{{- if .Version}} + +version: _@{{.Version}}_ +{{- end}} + {{- if .Description}} {{.Description}} diff --git a/operation.go b/operation.go index c503f5c..54c35f8 100644 --- a/operation.go +++ b/operation.go @@ -134,7 +134,7 @@ func (operation *Operation) ParseRequestComment(commentLine string, astFile *ast for _, p := range schema.Properties { tags := p.ParameterTags() if tags != nil { - if len(tags) > 0 && !p.HasJSONTag() { + if len(tags) > 0 && !p.hasJSONTag() { parameterCount++ } } diff --git a/parser.go b/parser.go index 2a431d4..82c5641 100644 --- a/parser.go +++ b/parser.go @@ -346,7 +346,6 @@ func walkWith(excludes map[string]struct{}) func(path string, fileInfo os.FileIn } } } - return nil } } @@ -361,15 +360,24 @@ func fullTypeName(pkgName, typeName string) string { func (parser *Parser) getTypeSchema(typeName string, file *ast.File, field *ast.Field, parentSchema *TypeSchema) (*TypeSchema, error) { if IsGolangPrimitiveType(typeName) { - name := field.Names[0].Name - return &TypeSchema{ - Name: name, - FullName: name, - Type: typeName, - Comment: strings.TrimSuffix(field.Comment.Text(), "\n"), - Parent: parentSchema, - TagValue: getAllTagValue(field), - }, nil + if field != nil { + name := field.Names[0].Name + return &TypeSchema{ + Name: name, + FullName: name, + Type: typeName, + Comment: strings.TrimSuffix(field.Comment.Text(), "\n"), + Parent: parentSchema, + TagValue: getAllTagValue(field), + }, nil + } else { + return &TypeSchema{ + Name: "", + FullName: typeName, + Type: typeName, + Parent: parentSchema, + }, nil + } } typeSpecDef := parser.packages.FindTypeSpec(typeName, file, true) @@ -412,9 +420,12 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field if err != nil { return nil, err } - if field != nil && field.Names != nil { - schema.Name = field.Names[0].Name + if field != nil { + if field.Names != nil { + schema.Name = field.Names[0].Name + } schema.TagValue = getAllTagValue(field) + schema.Comment = strings.TrimSuffix(field.Comment.Text(), "\n") } return schema, err case *ast.Ident: @@ -423,10 +434,6 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field if keyIdent, ok := expr.Key.(*ast.Ident); ok { if IsGolangPrimitiveType(keyIdent.Name) { example := strings.Trim(getFieldExample(keyIdent.Name, nil), "\"") //map key example - if _, ok := expr.Value.(*ast.InterfaceType); ok { - return &TypeSchema{Type: OBJECT, Properties: nil}, nil - } - mapSchema := &TypeSchema{ Type: OBJECT, Properties: map[string]*TypeSchema{}, @@ -438,7 +445,7 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef, field *ast.Field } mapSchema.TagValue = schema.TagValue mapSchema.Name = schema.Name - mapSchema.FullName = schema.FullName + mapSchema.FullName = fmt.Sprintf("map[%s]%s", keyIdent.Name, schema.FullName) schema.Name = example schema.TagValue = "" @@ -467,6 +474,7 @@ func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr a return &TypeSchema{ Name: field.Names[0].Name, Type: ANY, + FullName: ANY, Parent: parentSchema, TagValue: getAllTagValue(field), }, nil @@ -513,9 +521,6 @@ func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr a if keyIdent, ok := expr.Key.(*ast.Ident); ok { if IsGolangPrimitiveType(keyIdent.Name) { example := strings.Trim(getFieldExample(keyIdent.Name, nil), "\"") //map key example - if _, ok := expr.Value.(*ast.InterfaceType); ok { - return &TypeSchema{Type: OBJECT, Properties: nil}, nil - } mapSchema := &TypeSchema{ Type: OBJECT, Properties: map[string]*TypeSchema{}, @@ -527,7 +532,7 @@ func (parser *Parser) parseTypeExpr(file *ast.File, field *ast.Field, typeExpr a } mapSchema.TagValue = schema.TagValue mapSchema.Name = schema.Name - mapSchema.FullName = schema.FullName + mapSchema.FullName = fmt.Sprintf("map[%s]%s", keyIdent.Name, expr.Value) schema.Name = example schema.TagValue = "" @@ -564,6 +569,9 @@ func (parser *Parser) parseStruct(typeSpecDef *TypeSpecDef, file *ast.File, fiel if err != nil { return nil, err } + if schema == nil { + continue + } if field.Names == nil { //nested struct, replace with child properties for _, p := range schema.Properties { if _, ok := structSchema.Properties[strings.ToLower(p.Name)]; !ok { //if not exists key diff --git a/spec.go b/spec.go index 2aa9aac..1f6249d 100644 --- a/spec.go +++ b/spec.go @@ -7,6 +7,7 @@ import ( "sort" "strconv" "strings" + "time" ) type ApiDocSpec struct { @@ -148,7 +149,7 @@ func (s *TypeSchema) isIgnoreJsonKey() (isIgnore bool) { isIgnore = true return } - if s.parameterTags != nil && !s.HasJSONTag() { //request parameter ignore + if s.parameterTags != nil && !s.hasJSONTag() { //request parameter ignore isIgnore = true return } @@ -311,8 +312,11 @@ func (v *TypeSchema) buildComment() string { arrayName = v.ArraySchema.FullName } s += fmt.Sprintf("%s[%s]", ARRAY, arrayName) - } else if len(v.Properties) > 0 { //object - s += fmt.Sprintf("%s(%s)", v.Type, v.FullName) + } else if v.Type == OBJECT { //object + s += v.Type + if v.FullName != "" { + s += fmt.Sprintf("(%s)", v.FullName) + } } else { s += v.Type } @@ -353,26 +357,36 @@ func (v *TypeSchema) JSONKey() (key string, isOmitempty bool) { } } -func (v *TypeSchema) HasJSONTag() bool { +func (v *TypeSchema) hasJSONTag() bool { _, has := v.GetTag("json") return has } func (v *TypeSchema) ExampleValue() string { - if v.Type == ARRAY && v.ArraySchema == nil { - return NULL - } - if v.Type == OBJECT && (v.Properties == nil || len(v.Properties) == 0) { - return NULL - } if v.example != "" { return v.example } + if v.Type == ARRAY && v.ArraySchema == nil { + return NULL + } example := "" - if val, has := v.GetTag("example"); has { example = val } + + if v.Type == OBJECT && (v.Properties == nil || len(v.Properties) == 0) { + if v.FullName == "time.Time" { + if example != "" { + v.example = example + return v.example + } + b, _ := time.Now().MarshalJSON() + v.example = string(b) + return v.example + } + return NULL + } + v.example = getTypeExample(v.Type, example) return v.example }