Skip to content

Commit

Permalink
feat: use enums in request (#1417)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdghchj committed Dec 12, 2022
1 parent 9a4fa5d commit 4519064
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 87 deletions.
124 changes: 43 additions & 81 deletions operation.go
Expand Up @@ -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"
//
Expand All @@ -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, "[]")
Expand All @@ -298,30 +256,42 @@ 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(&param, paramType, refType, objectType)
if err != nil {
return err
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:
err := operation.parseArrayParam(&param, paramType, refType, objectType)
if err != nil {
return err
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:
schema, err := operation.parser.getTypeSchema(refType, astFile, false)
if err != nil {
Expand All @@ -344,20 +314,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]
param = createParameter(paramType, prop.Description, name, prop.Type[0], prop.Items.Schema.Type[0], findInSlice(schema.Required, name), enums, operation.parser.collectionFormatInQuery)

if operation.parser != nil && operation.parser.collectionFormatInQuery != "" && param.CollectionFormat == "" {
param.CollectionFormat = TransToValidCollectionFormat(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)

Expand Down Expand Up @@ -944,7 +904,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 {
Expand Down Expand Up @@ -1169,35 +1129,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
}

Expand Down
2 changes: 1 addition & 1 deletion parser.go
Expand Up @@ -546,7 +546,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:]
Expand Down
19 changes: 16 additions & 3 deletions testdata/enums/api/api.go
Expand Up @@ -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{}
}
56 changes: 54 additions & 2 deletions testdata/enums/expected.json
Expand Up @@ -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",
Expand All @@ -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": {
Expand Down

0 comments on commit 4519064

Please sign in to comment.