Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use enums in request #1417

Merged
merged 2 commits into from Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -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:]
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