Skip to content

Commit

Permalink
feat: default required option for struct fields (#1181)
Browse files Browse the repository at this point in the history
  • Loading branch information
underbek committed Jun 16, 2022
1 parent 213f6b8 commit a780e45
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 21 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -99,6 +99,7 @@ OPTIONS:
--codeExampleFiles value, --cef value Parse folder containing code example files to use for the x-codeSamples extension, disabled by default
--parseInternal Parse go files in internal packages, disabled by default (default: false)
--generatedTime Generate timestamp at the top of docs.go, disabled by default (default: false)
--requiredByDefault Set validation required for all fields by default (default: false)
--parseDepth value Dependency parse depth (default: 100)
--instanceName value This parameter can be used to name different swagger document instances. It is optional.
--overridesFile value File to read global type overrides from. (default: ".swaggo")
Expand Down Expand Up @@ -488,7 +489,7 @@ type Foo struct {

Field Name | Type | Description
---|:---:|---
<a name="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required`.
<a name="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required,optional`.
<a name="parameterDefault"></a>default | * | Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. (Note: "default" has no meaning for required parameters.) See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Unlike JSON Schema this value MUST conform to the defined [`type`](#parameterType) for this parameter.
<a name="parameterMaximum"></a>maximum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.
<a name="parameterMinimum"></a>minimum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.
Expand Down
40 changes: 23 additions & 17 deletions cmd/swag/main.go
Expand Up @@ -15,23 +15,24 @@ import (
)

const (
searchDirFlag = "dir"
excludeFlag = "exclude"
generalInfoFlag = "generalInfo"
propertyStrategyFlag = "propertyStrategy"
outputFlag = "output"
outputTypesFlag = "outputTypes"
parseVendorFlag = "parseVendor"
parseDependencyFlag = "parseDependency"
markdownFilesFlag = "markdownFiles"
codeExampleFilesFlag = "codeExampleFiles"
parseInternalFlag = "parseInternal"
generatedTimeFlag = "generatedTime"
parseDepthFlag = "parseDepth"
instanceNameFlag = "instanceName"
overridesFileFlag = "overridesFile"
parseGoListFlag = "parseGoList"
quietFlag = "quiet"
searchDirFlag = "dir"
excludeFlag = "exclude"
generalInfoFlag = "generalInfo"
propertyStrategyFlag = "propertyStrategy"
outputFlag = "output"
outputTypesFlag = "outputTypes"
parseVendorFlag = "parseVendor"
parseDependencyFlag = "parseDependency"
markdownFilesFlag = "markdownFiles"
codeExampleFilesFlag = "codeExampleFiles"
parseInternalFlag = "parseInternal"
generatedTimeFlag = "generatedTime"
requiredByDefaultFlag = "requiredByDefault"
parseDepthFlag = "parseDepth"
instanceNameFlag = "instanceName"
overridesFileFlag = "overridesFile"
parseGoListFlag = "parseGoList"
quietFlag = "quiet"
)

var initFlags = []cli.Flag{
Expand Down Expand Up @@ -108,6 +109,10 @@ var initFlags = []cli.Flag{
Value: 100,
Usage: "Dependency parse depth",
},
&cli.BoolFlag{
Name: requiredByDefaultFlag,
Usage: "Set validation required for all fields by default",
},
&cli.StringFlag{
Name: instanceNameFlag,
Value: "",
Expand Down Expand Up @@ -155,6 +160,7 @@ func initAction(ctx *cli.Context) error {
MarkdownFilesDir: ctx.String(markdownFilesFlag),
ParseInternal: ctx.Bool(parseInternalFlag),
GeneratedTime: ctx.Bool(generatedTimeFlag),
RequiredByDefault: ctx.Bool(requiredByDefaultFlag),
CodeExampleFilesDir: ctx.String(codeExampleFilesFlag),
ParseDepth: ctx.Int(parseDepthFlag),
InstanceName: ctx.String(instanceNameFlag),
Expand Down
13 changes: 10 additions & 3 deletions field_parser.go
Expand Up @@ -18,6 +18,7 @@ var _ FieldParser = &tagBaseFieldParser{p: nil, field: nil, tag: ""}

const (
requiredLabel = "required"
optionalLabel = "optional"
swaggerTypeTag = "swaggertype"
swaggerIgnoreTag = "swaggerignore"
)
Expand Down Expand Up @@ -472,22 +473,28 @@ func (ps *tagBaseFieldParser) IsRequired() (bool, error) {
bindingTag := ps.tag.Get(bindingTag)
if bindingTag != "" {
for _, val := range strings.Split(bindingTag, ",") {
if val == requiredLabel {
switch val {
case requiredLabel:
return true, nil
case optionalLabel:
return false, nil
}
}
}

validateTag := ps.tag.Get(validateTag)
if validateTag != "" {
for _, val := range strings.Split(validateTag, ",") {
if val == requiredLabel {
switch val {
case requiredLabel:
return true, nil
case optionalLabel:
return false, nil
}
}
}

return false, nil
return ps.p.RequiredByDefault, nil
}

func parseValidTags(validTag string, sf *structField) {
Expand Down
41 changes: 41 additions & 0 deletions field_parser_test.go
Expand Up @@ -82,6 +82,47 @@ func TestDefaultFieldParser(t *testing.T) {
assert.Equal(t, true, got)
})

t.Run("Default required tag", func(t *testing.T) {
t.Parallel()

got, err := newTagBaseFieldParser(
&Parser{
RequiredByDefault: true,
},
&ast.Field{Tag: &ast.BasicLit{
Value: `json:"test"`,
}},
).IsRequired()
assert.NoError(t, err)
assert.True(t, got)
})

t.Run("Optional tag", func(t *testing.T) {
t.Parallel()

got, err := newTagBaseFieldParser(
&Parser{
RequiredByDefault: true,
},
&ast.Field{Tag: &ast.BasicLit{
Value: `json:"test" binding:"optional"`,
}},
).IsRequired()
assert.NoError(t, err)
assert.False(t, got)

got, err = newTagBaseFieldParser(
&Parser{
RequiredByDefault: true,
},
&ast.Field{Tag: &ast.BasicLit{
Value: `json:"test" validate:"optional"`,
}},
).IsRequired()
assert.NoError(t, err)
assert.False(t, got)
})

t.Run("Extensions tag", func(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions gen/gen.go
Expand Up @@ -105,6 +105,9 @@ type Config struct {
// GeneratedTime whether swag should generate the timestamp at the top of docs.go
GeneratedTime bool

// RequiredByDefault set validation required for all fields by default
RequiredByDefault bool

// OverridesFile defines global type overrides.
OverridesFile string

Expand Down Expand Up @@ -159,6 +162,7 @@ func (g *Gen) Build(config *Config) error {
p.ParseVendor = config.ParseVendor
p.ParseDependency = config.ParseDependency
p.ParseInternal = config.ParseInternal
p.RequiredByDefault = config.RequiredByDefault

if err := p.ParseAPIMultiSearchDir(searchDirs, config.MainAPIFile, config.ParseDepth); err != nil {
return err
Expand Down
3 changes: 3 additions & 0 deletions parser.go
Expand Up @@ -130,6 +130,9 @@ type Parser struct {
// Strict whether swag should error or warn when it detects cases which are most likely user errors
Strict bool

// RequiredByDefault set validation required for all fields by default
RequiredByDefault bool

// structStack stores full names of the structures that were already parsed or are being parsed now
structStack []*TypeSpecDef

Expand Down

0 comments on commit a780e45

Please sign in to comment.