指定外层响应结构
This commit is contained in:
@ -239,21 +239,22 @@ type swaggerSchemaObject struct {
|
||||
|
||||
ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"`
|
||||
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
MultipleOf float64 `json:"multipleOf,omitempty"`
|
||||
Maximum float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength uint64 `json:"maxLength,omitempty"`
|
||||
MinLength uint64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems uint64 `json:"maxItems,omitempty"`
|
||||
MinItems uint64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MaxProperties uint64 `json:"maxProperties,omitempty"`
|
||||
MinProperties uint64 `json:"minProperties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
MultipleOf float64 `json:"multipleOf,omitempty"`
|
||||
Maximum float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength uint64 `json:"maxLength,omitempty"`
|
||||
MinLength uint64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems uint64 `json:"maxItems,omitempty"`
|
||||
MinItems uint64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MaxProperties uint64 `json:"maxProperties,omitempty"`
|
||||
MinProperties uint64 `json:"minProperties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
AllOf []swaggerSchemaObject `json:"allOf,omitempty"`
|
||||
}
|
||||
|
||||
// http://swagger.io/specification/#definitionsObject
|
||||
@ -269,3 +270,11 @@ type enumMap map[string]*descriptor.Enum
|
||||
|
||||
// Internal type to store used references.
|
||||
type refMap map[string]struct{}
|
||||
|
||||
// responseField 响应字段
|
||||
type responseField struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
IsData bool `json:"is_data"`
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/zeromicro/go-zero/tools/goctl/plugin"
|
||||
)
|
||||
|
||||
func Do(filename string, host string, basePath string, schemes string, in *plugin.Plugin) error {
|
||||
swagger, err := applyGenerate(in, host, basePath, schemes)
|
||||
func Do(filename, host, basePath, schemes, pack, response string, in *plugin.Plugin) error {
|
||||
swagger, err := applyGenerate(in, host, basePath, schemes, pack, response)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -24,7 +24,7 @@ func Do(filename string, host string, basePath string, schemes string, in *plugi
|
||||
|
||||
output := in.Dir + "/" + filename
|
||||
|
||||
err = ioutil.WriteFile(output, formatted.Bytes(), 0666)
|
||||
err = os.WriteFile(output, formatted.Bytes(), 0o666)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package generate
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -16,7 +17,10 @@ import (
|
||||
"github.com/zeromicro/go-zero/tools/goctl/plugin"
|
||||
)
|
||||
|
||||
var strColon = []byte(":")
|
||||
var (
|
||||
strColon = []byte(":")
|
||||
defaultResponse = parseDefaultResponse()
|
||||
)
|
||||
|
||||
const (
|
||||
validateKey = "validate"
|
||||
@ -30,6 +34,9 @@ const (
|
||||
optionSeparator = "|"
|
||||
equalToken = "="
|
||||
atRespDoc = "@respdoc-"
|
||||
|
||||
// DefaultResponseJson default response pack json structure.
|
||||
DefaultResponseJson = `[{"name":"trace_id","type":"string","description":"链路追踪id","example":"a1b2c3d4e5f6g7h8"},{"name":"code","type":"integer","description":"状态码","example":0},{"name":"msg","type":"string","description":"消息","example":"ok"},{"name":"data","type":"object","description":"数据","is_data":true}]`
|
||||
)
|
||||
|
||||
func parseRangeOption(option string) (float64, float64, bool) {
|
||||
@ -55,7 +62,7 @@ func parseRangeOption(option string) (float64, float64, bool) {
|
||||
return min, max, true
|
||||
}
|
||||
|
||||
func applyGenerate(p *plugin.Plugin, host string, basePath string, schemes string) (*swaggerObject, error) {
|
||||
func applyGenerate(p *plugin.Plugin, host, basePath, schemes, pack, response string) (*swaggerObject, error) {
|
||||
title, _ := strconv.Unquote(p.Api.Info.Properties["title"])
|
||||
version, _ := strconv.Unquote(p.Api.Info.Properties["version"])
|
||||
desc, _ := strconv.Unquote(p.Api.Info.Properties["desc"])
|
||||
@ -104,8 +111,22 @@ func applyGenerate(p *plugin.Plugin, host string, basePath string, schemes strin
|
||||
|
||||
// s.Security = append(s.Security, swaggerSecurityRequirementObject{"apiKey": []string{}})
|
||||
|
||||
dataKey := "data"
|
||||
if pack != "" {
|
||||
resp := defaultResponse
|
||||
if response != "" {
|
||||
r, dk, err := parseResponse(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = r
|
||||
dataKey = dk
|
||||
}
|
||||
s.Definitions[pack] = resp
|
||||
}
|
||||
|
||||
requestResponseRefs := refMap{}
|
||||
renderServiceRoutes(p.Api.Service, p.Api.Service.Groups, s.Paths, requestResponseRefs)
|
||||
renderServiceRoutes(p.Api.Service, p.Api.Service.Groups, s.Paths, requestResponseRefs, pack, dataKey)
|
||||
m := messageMap{}
|
||||
|
||||
renderReplyAsDefinition(s.Definitions, m, p.Api.Types, requestResponseRefs)
|
||||
@ -113,7 +134,7 @@ func applyGenerate(p *plugin.Plugin, host string, basePath string, schemes strin
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func renderServiceRoutes(service spec.Service, groups []spec.Group, paths swaggerPathsObject, requestResponseRefs refMap) {
|
||||
func renderServiceRoutes(service spec.Service, groups []spec.Group, paths swaggerPathsObject, requestResponseRefs refMap, pack, dataKey string) {
|
||||
for _, group := range groups {
|
||||
for _, route := range group.Routes {
|
||||
path := group.GetAnnotation("prefix") + route.Path
|
||||
@ -237,6 +258,17 @@ func renderServiceRoutes(service spec.Service, groups []spec.Group, paths swagge
|
||||
if value := group.GetAnnotation("swtags"); len(value) > 0 {
|
||||
tags = value
|
||||
}
|
||||
schema := swaggerSchemaObject{
|
||||
schemaCore: respSchema,
|
||||
}
|
||||
if pack != "" {
|
||||
schema = swaggerSchemaObject{
|
||||
AllOf: []swaggerSchemaObject{
|
||||
{schemaCore: schemaCore{Ref: "#/definitions/" + strings.TrimPrefix(pack, "/")}},
|
||||
{schemaCore: schemaCore{Type: "object"}, Properties: &swaggerSchemaObjectProperties{{Key: dataKey, Value: respSchema}}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
operationObject := &swaggerOperationObject{
|
||||
Tags: []string{tags},
|
||||
@ -244,9 +276,7 @@ func renderServiceRoutes(service spec.Service, groups []spec.Group, paths swagge
|
||||
Responses: swaggerResponsesObject{
|
||||
"200": swaggerResponseObject{
|
||||
Description: desc,
|
||||
Schema: swaggerSchemaObject{
|
||||
schemaCore: respSchema,
|
||||
},
|
||||
Schema: schema,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -520,7 +550,7 @@ func schemaOfField(member spec.Member) swaggerSchemaObject {
|
||||
comment = strings.Replace(comment, "//", "", -1)
|
||||
|
||||
switch ft := kind; ft {
|
||||
case reflect.Invalid: //[]Struct 也有可能是 Struct
|
||||
case reflect.Invalid: // []Struct 也有可能是 Struct
|
||||
// []Struct
|
||||
// map[ArrayType:map[Star:map[StringExpr:UserSearchReq] StringExpr:*UserSearchReq] StringExpr:[]*UserSearchReq]
|
||||
refTypeName := strings.Replace(member.Type.Name(), "[", "", 1)
|
||||
@ -769,3 +799,43 @@ func parseHeader(m spec.Member, parameters []swaggerParameterObject) []swaggerPa
|
||||
}
|
||||
return append(parameters, sp)
|
||||
}
|
||||
|
||||
// 解析响应参数
|
||||
func parseResponse(resp string) (swaggerSchemaObject, string, error) {
|
||||
var fields []responseField
|
||||
err := json.Unmarshal([]byte(resp), &fields)
|
||||
if err != nil {
|
||||
return swaggerSchemaObject{}, "", err
|
||||
}
|
||||
hasData := false
|
||||
dataKey := ""
|
||||
for _, field := range fields {
|
||||
if field.Name == "" || field.Type == "" {
|
||||
return swaggerSchemaObject{}, "", errors.New("响应字段参数错误")
|
||||
}
|
||||
if field.IsData {
|
||||
hasData = true
|
||||
dataKey = field.Name
|
||||
}
|
||||
}
|
||||
if !hasData {
|
||||
return swaggerSchemaObject{}, "", errors.New("请指定包装的数据字段")
|
||||
}
|
||||
properties := new(swaggerSchemaObjectProperties)
|
||||
response := swaggerSchemaObject{schemaCore: schemaCore{Type: "object"}}
|
||||
for _, field := range fields {
|
||||
*properties = append(*properties,
|
||||
keyVal{
|
||||
Key: field.Name,
|
||||
Value: swaggerSchemaObject{schemaCore: schemaCore{Type: field.Type}, Description: field.Description},
|
||||
})
|
||||
}
|
||||
response.Properties = properties
|
||||
return response, dataKey, nil
|
||||
}
|
||||
|
||||
// 默认返回值
|
||||
func parseDefaultResponse() swaggerSchemaObject {
|
||||
response, _, _ := parseResponse(DefaultResponseJson)
|
||||
return response
|
||||
}
|
||||
|
Reference in New Issue
Block a user