From d240c98f065dcb247849c99ff35c3b54ea745cc3 Mon Sep 17 00:00:00 2001 From: sdghchj Date: Fri, 9 Dec 2022 15:10:01 +0800 Subject: [PATCH 1/2] feat: enums in request --- operation.go | 129 +++++++++++------------------------ parser.go | 2 +- testdata/enums/api/api.go | 19 +++++- testdata/enums/expected.json | 56 ++++++++++++++- 4 files changed, 112 insertions(+), 94 deletions(-) diff --git a/operation.go b/operation.go index bd817ba7a..0da9c9b00 100644 --- a/operation.go +++ b/operation.go @@ -228,49 +228,6 @@ func findInSlice(arr []string, target string) bool { return false } -func (operation *Operation) parseArrayParam(param *spec.Parameter, paramType, refType, objectType string) error { - if !IsPrimitiveType(refType) && !(refType == "file" && paramType == "formData") { - return fmt.Errorf("%s is not supported array type for %s", refType, paramType) - } - - param.SimpleSchema.Type = objectType - - if operation.parser != nil { - param.CollectionFormat = TransToValidCollectionFormat(operation.parser.collectionFormatInQuery) - } - - param.SimpleSchema.Items = &spec.Items{ - SimpleSchema: spec.SimpleSchema{ - Default: nil, - Nullable: false, - Format: "", - Items: nil, - CollectionFormat: "", - Type: refType, - Example: nil, - }, - CommonValidations: spec.CommonValidations{ - Maximum: nil, - ExclusiveMaximum: false, - Minimum: nil, - ExclusiveMinimum: false, - MaxLength: nil, - MinLength: nil, - Pattern: "", - MaxItems: nil, - MinItems: nil, - UniqueItems: false, - MultipleOf: nil, - Enum: nil, - }, - VendorExtensible: spec.VendorExtensible{ - Extensions: nil, - }, - } - - return nil -} - // ParseParamComment parses params return []string of param properties // E.g. @Param queryText formData string true "The email for login" // @@ -289,6 +246,7 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F // Detect refType objectType := OBJECT + if strings.HasPrefix(refType, "[]") { objectType = ARRAY refType = strings.TrimPrefix(refType, "[]") @@ -298,30 +256,33 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F objectType = PRIMITIVE } + var enums []interface{} + if !IsPrimitiveType(refType) { + schema, _ := operation.parser.getTypeSchema(refType, astFile, false) + if schema != nil && len(schema.Type) == 1 && schema.Enum != nil { + if objectType == OBJECT { + objectType = PRIMITIVE + } + refType = TransToValidSchemeType(schema.Type[0]) + enums = schema.Enum + } + } + requiredText := strings.ToLower(matches[4]) required := requiredText == "true" || requiredText == requiredLabel description := matches[5] - param := createParameter(paramType, description, name, refType, required) + param := createParameter(paramType, description, name, objectType, refType, required, enums, operation.parser.collectionFormatInQuery) switch paramType { case "path", "header": - switch objectType { - case ARRAY: - err := operation.parseArrayParam(¶m, paramType, refType, objectType) - if err != nil { - return err - } - case OBJECT: - return fmt.Errorf("%s is not supported type for %s", refType, paramType) - } + break case "query", "formData": switch objectType { case ARRAY: - err := operation.parseArrayParam(¶m, paramType, refType, objectType) - if err != nil { - return err - } + break + case PRIMITIVE: + break case OBJECT: schema, err := operation.parser.getTypeSchema(refType, astFile, false) if err != nil { @@ -344,20 +305,10 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F case prop.Type[0] == ARRAY && prop.Items.Schema != nil && len(prop.Items.Schema.Type) > 0 && IsSimplePrimitiveType(prop.Items.Schema.Type[0]): - param = createParameter(paramType, prop.Description, name, prop.Type[0], findInSlice(schema.Required, name)) - param.SimpleSchema.Type = prop.Type[0] - - if operation.parser != nil && operation.parser.collectionFormatInQuery != "" && param.CollectionFormat == "" { - param.CollectionFormat = TransToValidCollectionFormat(operation.parser.collectionFormatInQuery) - } + param = createParameter(paramType, prop.Description, name, prop.Type[0], prop.Items.Schema.Type[0], findInSlice(schema.Required, name), enums, operation.parser.collectionFormatInQuery) - param.SimpleSchema.Items = &spec.Items{ - SimpleSchema: spec.SimpleSchema{ - Type: prop.Items.Schema.Type[0], - }, - } case IsSimplePrimitiveType(prop.Type[0]): - param = createParameter(paramType, prop.Description, name, prop.Type[0], findInSlice(schema.Required, name)) + param = createParameter(paramType, prop.Description, name, PRIMITIVE, prop.Type[0], findInSlice(schema.Required, name), enums, operation.parser.collectionFormatInQuery) default: operation.parser.debug.Printf("skip field [%s] in %s is not supported type for %s", name, refType, paramType) @@ -944,7 +895,7 @@ func parseCombinedObjectSchema(parser *Parser, refType string, astFile *ast.File func (operation *Operation) parseAPIObjectSchema(commentLine, schemaType, refType string, astFile *ast.File) (*spec.Schema, error) { if strings.HasSuffix(refType, ",") && strings.Contains(refType, "[") { - // regexp may have broken generics syntax. find closing bracket and add it back + // regexp may have broken generic syntax. find closing bracket and add it back allMatchesLenOffset := strings.Index(commentLine, refType) + len(refType) lostPartEndIdx := strings.Index(commentLine[allMatchesLenOffset:], "]") if lostPartEndIdx >= 0 { @@ -1169,35 +1120,37 @@ func (operation *Operation) AddResponse(code int, response *spec.Response) { } // createParameter returns swagger spec.Parameter for given paramType, description, paramName, schemaType, required. -func createParameter(paramType, description, paramName, schemaType string, required bool) spec.Parameter { +func createParameter(paramType, description, paramName, objectType, schemaType string, required bool, enums []interface{}, collectionFormat string) spec.Parameter { // //five possible parameter types. query, path, body, header, form result := spec.Parameter{ ParamProps: spec.ParamProps{ - Name: paramName, - Description: description, - Required: required, - In: paramType, - Schema: nil, - AllowEmptyValue: false, + Name: paramName, + Description: description, + Required: required, + In: paramType, }, } if paramType == "body" { - result.ParamProps.Schema = &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{schemaType}, - }, - } - return result } - result.SimpleSchema = spec.SimpleSchema{ - Type: schemaType, - Nullable: false, - Format: "", + switch objectType { + case ARRAY: + result.Type = objectType + result.CollectionFormat = collectionFormat + result.Items = &spec.Items{ + CommonValidations: spec.CommonValidations{ + Enum: enums, + }, + SimpleSchema: spec.SimpleSchema{ + Type: schemaType, + }, + } + case PRIMITIVE, OBJECT: + result.Type = schemaType + result.Enum = enums } - return result } diff --git a/parser.go b/parser.go index ea77311d5..9819dbf2d 100644 --- a/parser.go +++ b/parser.go @@ -536,7 +536,7 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error { parser.swagger.SecurityDefinitions[value] = scheme case "@query.collection.format": - parser.collectionFormatInQuery = value + parser.collectionFormatInQuery = TransToValidCollectionFormat(value) default: if strings.HasPrefix(attribute, "@x-") { extensionName := attribute[1:] diff --git a/testdata/enums/api/api.go b/testdata/enums/api/api.go index ea1766be0..1acbbcaca 100644 --- a/testdata/enums/api/api.go +++ b/testdata/enums/api/api.go @@ -2,12 +2,25 @@ package api import "github.com/swaggo/swag/testdata/enums/types" -// enum example +// post students // -// @Summary enums -// @Description enums +// @Summary test enums in response models +// @Description test enums in response models // @Failure 400 {object} types.Person "ok" // @Router /students [post] func API() { _ = types.Person{} } + +// get students +// +// @Summary test enums in response request +// @Description test enums in response request +// @Param typeinquery query []types.Type true "type" +// @Param typeinheader header types.Type true "type" +// @Param typeinpath path types.Type true "type" +// @Success 200 "ok" +// @Router /students/{typeinpath}/ [get] +func API2() { + _ = types.Person{} +} diff --git a/testdata/enums/expected.json b/testdata/enums/expected.json index 916f116ea..6cba6255d 100644 --- a/testdata/enums/expected.json +++ b/testdata/enums/expected.json @@ -19,8 +19,8 @@ "paths": { "/students": { "post": { - "description": "enums", - "summary": "enums", + "description": "test enums in response models", + "summary": "test enums in response models", "responses": { "400": { "description": "ok", @@ -30,6 +30,58 @@ } } } + }, + "/students/{typeinpath}/": { + "get": { + "description": "test enums in response request", + "summary": "test enums in response request", + "parameters": [ + { + "type": "array", + "items": { + "enum": [ + "teacher", + "student", + "Other" + ], + "type": "string" + }, + "description": "type", + "name": "typeinquery", + "in": "query", + "required": true + }, + { + "enum": [ + "teacher", + "student", + "Other" + ], + "type": "string", + "description": "type", + "name": "typeinheader", + "in": "header", + "required": true + }, + { + "enum": [ + "teacher", + "student", + "Other" + ], + "type": "string", + "description": "type", + "name": "typeinpath", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ok" + } + } + } } }, "definitions": { From de8ad3b5afee133c9583af169af50f37a546a32f Mon Sep 17 00:00:00 2001 From: sdghchj Date: Mon, 12 Dec 2022 15:06:06 +0800 Subject: [PATCH 2/2] fix test --- operation.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/operation.go b/operation.go index 0da9c9b00..8cadc6216 100644 --- a/operation.go +++ b/operation.go @@ -276,11 +276,20 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F switch paramType { case "path", "header": - break + switch objectType { + case ARRAY: + if !IsPrimitiveType(refType) { + return fmt.Errorf("%s is not supported array type for %s", refType, paramType) + } + case OBJECT: + return fmt.Errorf("%s is not supported type for %s", refType, paramType) + } case "query", "formData": switch objectType { case ARRAY: - break + if !IsPrimitiveType(refType) && !(refType == "file" && paramType == "formData") { + return fmt.Errorf("%s is not supported array type for %s", refType, paramType) + } case PRIMITIVE: break case OBJECT: