diff --git a/README.md b/README.md index d44b64f..87abc40 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ For example, if you had a Go backend that used the [Gin](https://www.github.com/ *The key features of Astra are:* * Extract types from web services * Read types from files +* Extracts [Go Validator V10](https://github.com/go-playground/validator) struct level validation * Follow through different functions to extract types * Extract types from any packages from the dependency tree * Adapt to different coding styles diff --git a/astTraversal/result.go b/astTraversal/result.go index 7c0b8cc..258ab12 100644 --- a/astTraversal/result.go +++ b/astTraversal/result.go @@ -46,10 +46,15 @@ type Result struct { // StructFields is a map of struct fields (e.g. for a struct { Foo string }) StructFields map[string]Result + // StructFieldBindingTags is a map of struct field binding tags (e.g. for a struct { Foo string `binding:"foo"` }) StructFieldBindingTags BindingTagMap + // StructFieldValidationTags is a map of struct field validation tags (e.g. for a struct { Foo string `validate:"unique"` }) StructFieldValidationTags ValidationTagMap + // StructFieldValidationRequired is a map of struct field validation required tags (e.g. for a struct { Foo string `validate:"required"` }) + StructFieldValidationRequired ValidationRequiredMap + // Doc is the documentation of the result Doc string } diff --git a/astTraversal/tags.go b/astTraversal/tags.go index 4be5a0f..681c14c 100644 --- a/astTraversal/tags.go +++ b/astTraversal/tags.go @@ -1,8 +1,12 @@ package astTraversal import ( + "go/types" "reflect" + "regexp" "strings" + + "github.com/ls6-events/validjsonator" ) type BindingTagType string @@ -37,13 +41,11 @@ const ( var ValidationTags = []ValidationTagType{GinValidationTag, ValidatorValidationTag} -type ValidationTag struct { - IsRequired bool `json:"is_required,omitempty" yaml:"is_required,omitempty"` -} +type ValidationTagMap map[ValidationTagType]validjsonator.Schema -type ValidationTagMap map[ValidationTagType]ValidationTag +type ValidationRequiredMap map[ValidationTagType]bool -func ParseStructTag(field string, tag string) (BindingTagMap, ValidationTagMap) { +func ParseStructTag(field string, node types.Type, tag string) (BindingTagMap, ValidationTagMap, ValidationRequiredMap) { bindingTags := make(BindingTagMap) for _, bindingTag := range BindingTags { tagValue, tagOk := reflect.StructTag(tag).Lookup(string(bindingTag)) @@ -75,16 +77,29 @@ func ParseStructTag(field string, tag string) (BindingTagMap, ValidationTagMap) } validationTags := make(ValidationTagMap) + validationRequired := make(ValidationRequiredMap) for _, validationTag := range ValidationTags { tagValue := reflect.StructTag(tag).Get(string(validationTag)) if tagValue == "" { continue } - validationTags[validationTag] = ValidationTag{ - IsRequired: strings.Contains(tagValue, "required"), + splitValues := regexp.MustCompile(`\s*,?\s*dive\s*,?\s*`).Split(tagValue, 2) + baseSchema, required := validjsonator.ValidationTagsToSchema(splitValues[0]) + + if len(splitValues) == 2 { + diveSchema, _ := validjsonator.ValidationTagsToSchema(splitValues[1]) + + switch node.(type) { + case *types.Slice: + baseSchema.Items = &diveSchema + case *types.Map: + baseSchema.AdditionalProperties = &diveSchema + } } + + validationTags[validationTag], validationRequired[validationTag] = baseSchema, required } - return bindingTags, validationTags + return bindingTags, validationTags, validationRequired } diff --git a/astTraversal/tags_test.go b/astTraversal/tags_test.go index c2bd289..6514eec 100644 --- a/astTraversal/tags_test.go +++ b/astTraversal/tags_test.go @@ -1,20 +1,22 @@ package astTraversal import ( + "go/types" "reflect" "testing" ) func TestParseStructTag(t *testing.T) { testCases := []struct { - field string - tag string - expectedBindingTags BindingTagMap - expectedValidationTags ValidationTagMap + field string + tag string + node types.Type + expectedBindingTags BindingTagMap }{ { field: "Field1", tag: `json:"field1"`, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ JSONBindingTag: { Name: "field1", @@ -22,11 +24,11 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: false, }, }, - expectedValidationTags: ValidationTagMap{}, }, { field: "Field2", tag: `json:"field2,omitempty"`, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ JSONBindingTag: { Name: "field2", @@ -34,11 +36,11 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: true, }, }, - expectedValidationTags: ValidationTagMap{}, }, { field: "Field3", tag: `json:""`, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ JSONBindingTag: { Name: "Field3", @@ -46,11 +48,11 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: false, }, }, - expectedValidationTags: ValidationTagMap{}, }, { field: "Field4", tag: `json:",omitempty"`, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ JSONBindingTag: { Name: "Field4", @@ -58,11 +60,11 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: true, }, }, - expectedValidationTags: ValidationTagMap{}, }, { field: "Field5", tag: `json:"-"`, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ JSONBindingTag: { Name: "", @@ -70,27 +72,11 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: false, }, }, - expectedValidationTags: ValidationTagMap{}, - }, - { - field: "Field6", - tag: `validate:"required"`, - expectedBindingTags: BindingTagMap{ - NoBindingTag: { - Name: "Field6", - NotShown: false, - ReturnOptional: false, - }, - }, - expectedValidationTags: ValidationTagMap{ - ValidatorValidationTag: { - IsRequired: true, - }, - }, }, { field: "Field7", tag: ``, + node: &types.Basic{}, expectedBindingTags: BindingTagMap{ NoBindingTag: { Name: "Field7", @@ -98,21 +84,16 @@ func TestParseStructTag(t *testing.T) { ReturnOptional: false, }, }, - expectedValidationTags: ValidationTagMap{}, }, } for _, testCase := range testCases { t.Run("field="+testCase.field, func(t *testing.T) { - bindingTags, validationTags := ParseStructTag(testCase.field, testCase.tag) + bindingTags, _, _ := ParseStructTag(testCase.field, testCase.node, testCase.tag) if !reflect.DeepEqual(bindingTags, testCase.expectedBindingTags) { t.Errorf("Expected BindingTags: %v, but got: %v", testCase.expectedBindingTags, bindingTags) } - - if !reflect.DeepEqual(validationTags, testCase.expectedValidationTags) { - t.Errorf("Expected ValidationTags: %v, but got: %v", testCase.expectedValidationTags, validationTags) - } }) } } diff --git a/astTraversal/type.go b/astTraversal/type.go index aca6adf..dce2e04 100644 --- a/astTraversal/type.go +++ b/astTraversal/type.go @@ -204,20 +204,23 @@ func (t *TypeTraverser) Result() (Result, error) { case *types.Struct: fields := make(map[string]Result) for i := 0; i < n.NumFields(); i++ { - f := n.Field(i) - name := f.Id() - isExported := f.Exported() - isEmbedded := f.Embedded() + tag := n.Tag(i) + field := n.Field(i) + name := field.Id() + node := field.Type() + isExported := field.Exported() + isEmbedded := field.Embedded() + + if !isExported { + continue + } var bindingTag BindingTagMap var validationTags ValidationTagMap - if isExported { - bindingTag, validationTags = ParseStructTag(name, n.Tag(i)) - } else { - continue - } + var validationRequired ValidationRequiredMap + bindingTag, validationTags, validationRequired = ParseStructTag(name, node, tag) - structFieldResult, err := t.Traverser.Type(f.Type(), t.Package).Result() + structFieldResult, err := t.Traverser.Type(node, t.Package).Result() if err != nil { return Result{}, err } @@ -228,7 +231,7 @@ func (t *TypeTraverser) Result() (Result, error) { return Result{}, err } - pos := f.Pos() + pos := field.Pos() node, err := structFieldResult.Package.ASTAtPos(pos) if err == nil && node != nil { @@ -242,6 +245,7 @@ func (t *TypeTraverser) Result() (Result, error) { structFieldResult.IsEmbedded = isEmbedded structFieldResult.StructFieldBindingTags = bindingTag structFieldResult.StructFieldValidationTags = validationTags + structFieldResult.StructFieldValidationRequired = validationRequired fields[name] = structFieldResult } diff --git a/astTraversal/type_test.go b/astTraversal/type_test.go index 4a7194e..70e53fc 100644 --- a/astTraversal/type_test.go +++ b/astTraversal/type_test.go @@ -82,7 +82,7 @@ func TestTypeTraverser_Result(t *testing.T) { ageField, ok := res.StructFields["Age"] assert.True(t, ok) assert.Equal(t, "int", ageField.Type) - assert.True(t, ageField.StructFieldValidationTags[GinValidationTag].IsRequired) + assert.True(t, ageField.StructFieldValidationRequired[GinValidationTag]) }) } diff --git a/cli/astra/go.mod b/cli/astra/go.mod index 9ec6383..229bfa9 100644 --- a/cli/astra/go.mod +++ b/cli/astra/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -26,13 +27,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect diff --git a/cli/astra/go.sum b/cli/astra/go.sum index 61a9b20..6f586f1 100644 --- a/cli/astra/go.sum +++ b/cli/astra/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -45,6 +47,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -63,8 +67,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= diff --git a/examples/basic/go.mod b/examples/basic/go.mod index 678601f..410617d 100644 --- a/examples/basic/go.mod +++ b/examples/basic/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/basic/go.sum b/examples/basic/go.sum index b95ac74..4574dfe 100644 --- a/examples/basic/go.sum +++ b/examples/basic/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/taskfile.yml b/examples/taskfile.yml index 892a700..48e8662 100644 --- a/examples/taskfile.yml +++ b/examples/taskfile.yml @@ -12,10 +12,21 @@ includes: with-gorm: ./with-gorm/taskfile.yml with-multi-content-types: ./with-multi-content-types/taskfile.yml with-swagger-ui: ./with-swagger-ui/taskfile.yml + with-validation: ./with-validation/taskfile.yml tasks: run: - cmds: - - for: [basic, with-azure-functions, with-cache, with-cli, with-cobra, with-custom-functions, with-custom-type-mapping, with-gorm, with-multi-content-types, with-swagger-ui] - cmd: cd {{ .ITEM }} && task run - + cmds: + - for: + - basic + - with-azure-functions + - with-cache + - with-cli + - with-cobra + - with-custom-functions + - with-custom-type-mapping + - with-gorm + - with-multi-content-types + - with-swagger-ui + - with-validation + cmd: cd {{ .ITEM }} && task run diff --git a/examples/with-azure-functions/go.mod b/examples/with-azure-functions/go.mod index bdee99c..914c3fa 100644 --- a/examples/with-azure-functions/go.mod +++ b/examples/with-azure-functions/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-azure-functions/go.sum b/examples/with-azure-functions/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-azure-functions/go.sum +++ b/examples/with-azure-functions/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-cache/go.mod b/examples/with-cache/go.mod index 2dd80bd..2b955b2 100644 --- a/examples/with-cache/go.mod +++ b/examples/with-cache/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-cache/go.sum b/examples/with-cache/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-cache/go.sum +++ b/examples/with-cache/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-cli/go.mod b/examples/with-cli/go.mod index 4602845..6a7fa07 100644 --- a/examples/with-cli/go.mod +++ b/examples/with-cli/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-cli/go.sum b/examples/with-cli/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-cli/go.sum +++ b/examples/with-cli/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-cobra/go.mod b/examples/with-cobra/go.mod index cbb44e7..075b64f 100644 --- a/examples/with-cobra/go.mod +++ b/examples/with-cobra/go.mod @@ -11,6 +11,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -26,13 +27,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect diff --git a/examples/with-cobra/go.sum b/examples/with-cobra/go.sum index 61a9b20..6f586f1 100644 --- a/examples/with-cobra/go.sum +++ b/examples/with-cobra/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -45,6 +47,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -63,8 +67,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= diff --git a/examples/with-cobra/taskfile.yml b/examples/with-cobra/taskfile.yml index 362b843..01b5670 100644 --- a/examples/with-cobra/taskfile.yml +++ b/examples/with-cobra/taskfile.yml @@ -4,5 +4,6 @@ version: '3' tasks: run: cmds: + - go mod tidy - go run . generate diff --git a/examples/with-custom-functions/go.mod b/examples/with-custom-functions/go.mod index a207527..7df824a 100644 --- a/examples/with-custom-functions/go.mod +++ b/examples/with-custom-functions/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-custom-functions/go.sum b/examples/with-custom-functions/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-custom-functions/go.sum +++ b/examples/with-custom-functions/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-custom-type-mapping/go.mod b/examples/with-custom-type-mapping/go.mod index 8fcaf7f..364676d 100644 --- a/examples/with-custom-type-mapping/go.mod +++ b/examples/with-custom-type-mapping/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-custom-type-mapping/go.sum b/examples/with-custom-type-mapping/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-custom-type-mapping/go.sum +++ b/examples/with-custom-type-mapping/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-gorm/go.mod b/examples/with-gorm/go.mod index 76df0d9..e66e766 100644 --- a/examples/with-gorm/go.mod +++ b/examples/with-gorm/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -28,6 +29,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect @@ -35,7 +37,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-gorm/go.sum b/examples/with-gorm/go.sum index f1959b5..8223a7b 100644 --- a/examples/with-gorm/go.sum +++ b/examples/with-gorm/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -46,6 +48,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -66,8 +70,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-multi-content-types/go.mod b/examples/with-multi-content-types/go.mod index a061270..d2e45a6 100644 --- a/examples/with-multi-content-types/go.mod +++ b/examples/with-multi-content-types/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-multi-content-types/go.sum b/examples/with-multi-content-types/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-multi-content-types/go.sum +++ b/examples/with-multi-content-types/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-multi-content-types/openapi.generated.yaml b/examples/with-multi-content-types/openapi.generated.yaml index 878e6c6..a534678 100644 --- a/examples/with-multi-content-types/openapi.generated.yaml +++ b/examples/with-multi-content-types/openapi.generated.yaml @@ -289,12 +289,16 @@ components: name: type: string types.json.PostID: + required: + - id type: object properties: id: type: integer format: int32 types.uri.PostID: + required: + - postID type: object properties: postID: @@ -348,6 +352,8 @@ components: name: type: string types.yaml.PostID: + required: + - id type: object properties: id: diff --git a/examples/with-swagger-ui/go.mod b/examples/with-swagger-ui/go.mod index 90ab2f1..6c0c60f 100644 --- a/examples/with-swagger-ui/go.mod +++ b/examples/with-swagger-ui/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -24,13 +25,14 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rs/zerolog v1.32.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.8.0 // indirect diff --git a/examples/with-swagger-ui/go.sum b/examples/with-swagger-ui/go.sum index b95ac74..4574dfe 100644 --- a/examples/with-swagger-ui/go.sum +++ b/examples/with-swagger-ui/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -42,6 +44,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,8 +64,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/examples/with-validation/README.md b/examples/with-validation/README.md new file mode 100644 index 0000000..7203212 --- /dev/null +++ b/examples/with-validation/README.md @@ -0,0 +1,16 @@ +# Basic Example +This is a basic example of how to use the Astra API with struct validation from [go validator v10](https://github.com/go-playground/validator) package. It utilises some basic features of the API, and some basic types for CRUD operations for a blog system. The results and data are faked, but the important thing to note here is that the types are carried through the entire system, and Astra can be used to generate a full CRUD system with a few lines of code. + +## Running the example + +To run the example, you need to have a working Go installation. You can run the example by running: + +```bash +go run . +``` + +## Important files + +The important files in this example are: +* `main.go` - This is the main file that runs the example. +* `openapi.generated.yaml` - This is the OpenAPI file that is generated by Astra. \ No newline at end of file diff --git a/examples/with-validation/createPost.go b/examples/with-validation/createPost.go new file mode 100644 index 0000000..e7e612a --- /dev/null +++ b/examples/with-validation/createPost.go @@ -0,0 +1,32 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "net/http" + "time" + "withvalidation/types" +) + +func CreatePost(c *gin.Context) { + var postDTO types.PostDTO + err := c.ShouldBindJSON(&postDTO) + if err != nil { + c.String(http.StatusBadRequest, "Invalid post") + return + } + + post := types.Post{ + ID: uuid.New().String(), + Name: postDTO.Name, + Body: postDTO.Body, + PublishedAt: time.Now(), + Author: types.Author{ + ID: postDTO.AuthorID, + FirstName: "John", + LastName: "Doe", + }, + } + + c.JSON(http.StatusOK, post) +} diff --git a/examples/with-validation/deletePost.go b/examples/with-validation/deletePost.go new file mode 100644 index 0000000..033fe0f --- /dev/null +++ b/examples/with-validation/deletePost.go @@ -0,0 +1,16 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +func DeletePost(c *gin.Context) { + postId := c.Param("id") + + if postId == "" { + c.String(http.StatusBadRequest, "Missing post id") + } + + c.Status(http.StatusOK) +} diff --git a/examples/with-validation/getPost.go b/examples/with-validation/getPost.go new file mode 100644 index 0000000..6888a5a --- /dev/null +++ b/examples/with-validation/getPost.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "net/http" + "time" + "withvalidation/types" +) + +func GetPost(c *gin.Context) { + postId := c.Param("id") + + if postId == "" { + c.String(http.StatusBadRequest, "Missing post id") + } + + c.JSON(http.StatusOK, types.Post{ + ID: uuid.New().String(), + Name: "Second post", + Body: "This is the second post", + PublishedAt: time.Now(), + Author: types.Author{ + ID: uuid.New().String(), + FirstName: "Jane", + LastName: "Doe", + }, + }) +} diff --git a/examples/with-validation/getPosts.go b/examples/with-validation/getPosts.go new file mode 100644 index 0000000..c92abd9 --- /dev/null +++ b/examples/with-validation/getPosts.go @@ -0,0 +1,39 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "net/http" + "time" + "withvalidation/types" +) + +func GetPosts(c *gin.Context) { + posts := make([]types.Post, 0) + + posts = append(posts, types.Post{ + ID: uuid.New().String(), + Name: "First post", + Body: "This is the first post", + PublishedAt: time.Now(), + Author: types.Author{ + ID: uuid.New().String(), + FirstName: "John", + LastName: "Doe", + }, + }) + + posts = append(posts, types.Post{ + ID: uuid.New().String(), + Name: "Second post", + Body: "This is the second post", + PublishedAt: time.Now(), + Author: types.Author{ + ID: uuid.New().String(), + FirstName: "Jane", + LastName: "Doe", + }, + }) + + c.JSON(http.StatusOK, posts) +} diff --git a/examples/with-validation/go.mod b/examples/with-validation/go.mod new file mode 100644 index 0000000..2620591 --- /dev/null +++ b/examples/with-validation/go.mod @@ -0,0 +1,49 @@ +module withvalidation + +go 1.21 + +replace github.com/ls6-events/astra => ../../ + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/google/uuid v1.6.0 + github.com/ls6-events/astra v1.22.0 +) + +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/ls6-events/validjsonator v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rs/zerolog v1.33.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + golang.org/x/tools v0.21.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/with-validation/go.sum b/examples/with-validation/go.sum new file mode 100644 index 0000000..5a7ada0 --- /dev/null +++ b/examples/with-validation/go.sum @@ -0,0 +1,116 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= +github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/examples/with-validation/main.go b/examples/with-validation/main.go new file mode 100644 index 0000000..52f2556 --- /dev/null +++ b/examples/with-validation/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/ls6-events/astra" + "github.com/ls6-events/astra/inputs" + "github.com/ls6-events/astra/outputs" +) + +func main() { + r := gin.Default() + + r.GET("/posts", GetPosts) + r.GET("/posts/:id", GetPost) + r.POST("/posts", CreatePost) + r.PUT("/posts/:id", UpdatePost) + r.DELETE("/posts/:id", DeletePost) + + r.GET("/health", func(c *gin.Context) { + c.JSON(200, gin.H{ + "status": "ok", + }) + }) + + gen := astra.New(inputs.WithGinInput(r), outputs.WithOpenAPIOutput("openapi.generated.yaml")) + + config := astra.Config{ + Title: "Example API", + Version: "1.0.0", + Host: "localhost", + Port: 8000, + } + + gen.SetConfig(&config) + + err := gen.Parse() + if err != nil { + panic(err) + } + + err = r.Run(":8000") + if err != nil { + panic(err) + } +} diff --git a/examples/with-validation/openapi.generated.yaml b/examples/with-validation/openapi.generated.yaml new file mode 100644 index 0000000..c38d962 --- /dev/null +++ b/examples/with-validation/openapi.generated.yaml @@ -0,0 +1,250 @@ +openapi: 3.0.0 +info: + title: Example API + description: Generated by astra + contact: {} + license: + name: "" + version: 1.0.0 +servers: + - url: http://localhost:8000 +paths: + /health: + get: + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: '#/components/schemas/gin.H' + /posts: + get: + operationId: getPosts + responses: + "200": + description: "" + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/types.Post' + post: + operationId: createPost + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.PostDTO' + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: '#/components/schemas/types.Post' + "400": + description: "" + content: + text/plain: + schema: + type: string + /posts/{id}: + get: + operationId: getPost + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: '#/components/schemas/types.Post' + "400": + description: "" + content: + text/plain: + schema: + type: string + put: + operationId: updatePost + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.PostDTO' + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: '#/components/schemas/types.Post' + "400": + description: "" + content: + text/plain: + schema: + type: string + delete: + operationId: deletePost + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "200": + description: "" + "400": + description: "" + content: + text/plain: + schema: + type: string +components: + schemas: + gin.H: + type: object + additionalProperties: {} + description: H is a shortcut for map[string]any + time.Time: + type: string + format: date-time + description: |- + A Time represents an instant in time with nanosecond precision. + + Programs using times should typically store and pass them as values, + not pointers. That is, time variables and struct fields should be of + type time.Time, not *time.Time. + + A Time value can be used by multiple goroutines simultaneously except + that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and + UnmarshalText are not concurrency-safe. + + Time instants can be compared using the Before, After, and Equal methods. + The Sub method subtracts two instants, producing a Duration. + The Add method adds a Time and a Duration, producing a Time. + + The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. + As this time is unlikely to come up in practice, the IsZero method gives + a simple way of detecting a time that has not been initialized explicitly. + + Each Time has associated with it a Location, consulted when computing the + presentation form of the time, such as in the Format, Hour, and Year methods. + The methods Local, UTC, and In return a Time with a specific location. + Changing the location in this way changes only the presentation; it does not + change the instant in time being denoted and therefore does not affect the + computations described in earlier paragraphs. + + Representations of a Time value saved by the GobEncode, MarshalBinary, + MarshalJSON, and MarshalText methods store the Time.Location's offset, but not + the location name. They therefore lose information about Daylight Saving Time. + + In addition to the required “wall clock” reading, a Time may contain an optional + reading of the current process's monotonic clock, to provide additional precision + for comparison or subtraction. + See the “Monotonic Clocks” section in the package documentation for details. + + Note that the Go == operator compares not just the time instant but also the + Location and the monotonic clock reading. Therefore, Time values should not + be used as map or database keys without first guaranteeing that the + identical Location has been set for all values, which can be achieved + through use of the UTC or Local method, and that the monotonic clock reading + has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) + to t == u, since t.Equal uses the most accurate comparison available and + correctly handles the case when only one of its arguments has a monotonic + clock reading. + types.Author: + required: + - first_name + - last_name + - id + type: object + properties: + first_name: + type: string + id: + type: string + allOf: + - format: uuid + last_name: + type: string + types.Comment: + required: + - id + - body + - author + type: object + properties: + author: + $ref: '#/components/schemas/types.Author' + body: + type: string + allOf: + - maximum: 256 + exclusiveMaximum: true + id: + type: string + allOf: + - format: uuid + types.Post: + required: + - comments + - id + - name + - published_at + - author + type: object + properties: + author: + $ref: '#/components/schemas/types.Author' + body: + type: string + allOf: + - maximum: 512 + exclusiveMaximum: true + comments: + type: array + allOf: + - uniqueItems: true + items: + $ref: '#/components/schemas/types.Comment' + id: + type: string + allOf: + - format: uuid + name: + type: string + published_at: + $ref: '#/components/schemas/time.Time' + types.PostDTO: + required: + - author_id + - name + type: object + properties: + author_id: + type: string + allOf: + - format: uuid + body: + type: string + allOf: + - maximum: 512 + exclusiveMaximum: true + name: + type: string diff --git a/examples/with-validation/taskfile.yml b/examples/with-validation/taskfile.yml new file mode 100644 index 0000000..bc98b94 --- /dev/null +++ b/examples/with-validation/taskfile.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://taskfile.dev/schema.json +version: '3' + +tasks: + run: + cmds: + - go mod tidy + - . ../run-and-stop-server.sh + diff --git a/examples/with-validation/types/author.go b/examples/with-validation/types/author.go new file mode 100644 index 0000000..d89feea --- /dev/null +++ b/examples/with-validation/types/author.go @@ -0,0 +1,7 @@ +package types + +type Author struct { + ID string `json:"id" binding:"required,uuid4"` + FirstName string `json:"first_name" binding:"required"` + LastName string `json:"last_name" binding:"required"` +} diff --git a/examples/with-validation/types/comment.go b/examples/with-validation/types/comment.go new file mode 100644 index 0000000..de6613e --- /dev/null +++ b/examples/with-validation/types/comment.go @@ -0,0 +1,7 @@ +package types + +type Comment struct { + ID string `json:"id" binding:"required,uuid4"` + Body string `json:"body" binding:"required,max=256"` + Author Author `json:"author" binding:"required"` +} diff --git a/examples/with-validation/types/post.go b/examples/with-validation/types/post.go new file mode 100644 index 0000000..6578090 --- /dev/null +++ b/examples/with-validation/types/post.go @@ -0,0 +1,18 @@ +package types + +import "time" + +type Post struct { + ID string `json:"id" binding:"required,uuid4"` + Name string `json:"name" binding:"required"` + Body string `json:"body" binding:"max=512"` + PublishedAt time.Time `json:"published_at" binding:"required"` + Author Author `json:"author" binding:"required"` + Comments []Comment `json:"comments" binding:"required,unique"` +} + +type PostDTO struct { + Name string `json:"name" binding:"required"` + Body string `json:"body" binding:"max=512"` + AuthorID string `json:"author_id" binding:"required,uuid4"` +} diff --git a/examples/with-validation/updatePost.go b/examples/with-validation/updatePost.go new file mode 100644 index 0000000..85b37b2 --- /dev/null +++ b/examples/with-validation/updatePost.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "net/http" + "withvalidation/types" +) + +func UpdatePost(c *gin.Context) { + postId := c.Param("id") + + if postId == "" { + c.String(http.StatusBadRequest, "Missing post id") + } + + var postDTO types.PostDTO + err := c.ShouldBindJSON(&postDTO) + if err != nil { + c.String(http.StatusBadRequest, "Invalid post") + return + } + + post := types.Post{ + ID: postId, + Name: postDTO.Name, + Body: postDTO.Body, + } + + c.JSON(http.StatusOK, post) +} diff --git a/go.mod b/go.mod index b3df893..63aca13 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module github.com/ls6-events/astra go 1.21 require ( + dario.cat/mergo v1.0.0 github.com/Jeffail/gabs/v2 v2.7.0 github.com/gin-gonic/gin v1.10.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/iancoleman/strcase v0.3.0 + github.com/ls6-events/validjsonator v1.1.0 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 golang.org/x/tools v0.21.0 diff --git a/go.sum b/go.sum index d6a9f62..5a7ada0 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -44,6 +46,8 @@ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/ls6-events/validjsonator v1.1.0 h1:sKRPoULrVnI5AP0HeDDOEQxGmtyI+4yANrScrM/PpW0= +github.com/ls6-events/validjsonator v1.1.0/go.mod h1:GjTuaM3Y/bymNDAJLkziXHbApT/xtoxixQWgggdNxsY= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= diff --git a/outputs/openapi/components.go b/outputs/openapi/components.go index 68405fd..e9b914e 100644 --- a/outputs/openapi/components.go +++ b/outputs/openapi/components.go @@ -4,8 +4,11 @@ import ( "slices" "strings" + "dario.cat/mergo" + "github.com/ls6-events/astra" "github.com/ls6-events/astra/astTraversal" + "github.com/ls6-events/validjsonator" ) // collisionSafeNames is a map of a full name package path to a collision safe name. @@ -133,16 +136,16 @@ func makeComponentRefName(bindingType astTraversal.BindingTagType, name, pkg str } // componentToSchema converts a component to a schema. -func componentToSchema(service *astra.Service, component astra.Field, bindingType astTraversal.BindingTagType) (schema Schema, bound bool) { +func componentToSchema(service *astra.Service, component astra.Field, bindingType astTraversal.BindingTagType) (schema validjsonator.Schema, bound bool) { if _, ok := service.GetTypeMapping(component.Name, component.Package); ok { return mapTypeFormat(service, component.Name, component.Package), true } if component.Type == "struct" { - embeddedProperties := make([]Schema, 0) - schema = Schema{ + embeddedProperties := make([]validjsonator.Schema, 0) + schema = validjsonator.Schema{ Type: "object", - Properties: make(map[string]Schema), + Properties: make(map[string]validjsonator.Schema), } for _, field := range component.StructFields { // We should aim to use doc comments in the future. @@ -150,7 +153,7 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if field.IsEmbedded { componentRef, componentBound := makeComponentRef(bindingType, field.Type, field.Package) if componentBound { - embeddedProperties = append(embeddedProperties, Schema{ + embeddedProperties = append(embeddedProperties, validjsonator.Schema{ Ref: componentRef, }) } @@ -161,7 +164,7 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp fieldBinding := field.StructFieldBindingTags[bindingType] fieldNoBinding := field.StructFieldBindingTags[astTraversal.NoBindingTag] if fieldBinding == (astTraversal.BindingTag{}) && fieldNoBinding == (astTraversal.BindingTag{}) { - return Schema{}, false + return validjsonator.Schema{}, false } if fieldBinding == (astTraversal.BindingTag{}) { fieldBinding = fieldNoBinding @@ -170,7 +173,17 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if !fieldBinding.NotShown { fieldSchema, fieldBound := componentToSchema(service, field, bindingType) if fieldBound { + err := mergo.Merge(&fieldSchema, field.StructFieldValidationTags[astTraversal.GinValidationTag]) + if err != nil { + service.Log.Warn().Err(err).Msg("failed to merge component and validation schemas") + continue + } + schema.Properties[fieldBinding.Name] = fieldSchema + + if field.StructFieldValidationRequired[astTraversal.GinValidationTag] { + schema.Required = append(schema.Required, fieldBinding.Name) + } } } } @@ -179,7 +192,7 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if len(schema.Properties) == 0 { schema.AllOf = embeddedProperties } else { - schema.AllOf = append(embeddedProperties, Schema{ + schema.AllOf = append(embeddedProperties, validjsonator.Schema{ Properties: schema.Properties, }) @@ -192,13 +205,13 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if itemSchema.Type == "" && !astra.IsAcceptedType(component.SliceType) { componentRef, componentBound := makeComponentRef(bindingType, component.SliceType, component.Package) if componentBound { - itemSchema = Schema{ + itemSchema = validjsonator.Schema{ Ref: componentRef, } } } - schema = Schema{ + schema = validjsonator.Schema{ Type: "array", Items: &itemSchema, } @@ -208,13 +221,13 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if itemSchema.Type == "" && !astra.IsAcceptedType(component.ArrayType) { componentRef, componentBound := makeComponentRef(bindingType, component.ArrayType, component.Package) if componentBound { - itemSchema = Schema{ + itemSchema = validjsonator.Schema{ Ref: componentRef, } } } - schema = Schema{ + schema = validjsonator.Schema{ Type: "array", Items: &itemSchema, MaxLength: int(component.ArrayLength), @@ -229,7 +242,7 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp } } - schema = Schema{ + schema = validjsonator.Schema{ Type: "object", AdditionalProperties: &additionalProperties, } @@ -238,7 +251,7 @@ func componentToSchema(service *astra.Service, component astra.Field, bindingTyp if schema.Type == "" && !astra.IsAcceptedType(component.Type) { componentRef, componentBound := makeComponentRef(bindingType, component.Type, component.Package) if componentBound { - schema = Schema{ + schema = validjsonator.Schema{ Ref: componentRef, } } diff --git a/outputs/openapi/generate.go b/outputs/openapi/generate.go index 7829bbf..4a26b61 100644 --- a/outputs/openapi/generate.go +++ b/outputs/openapi/generate.go @@ -14,6 +14,7 @@ import ( "github.com/ls6-events/astra" "github.com/ls6-events/astra/astTraversal" "github.com/ls6-events/astra/utils" + "github.com/ls6-events/validjsonator" "gopkg.in/yaml.v3" ) @@ -152,9 +153,9 @@ func Generate(filePath string) astra.ServiceFunction { var mediaType MediaType if bodyParam.Name != "" { - mediaType.Schema = Schema{ + mediaType.Schema = validjsonator.Schema{ Type: "object", - Properties: map[string]Schema{ + Properties: map[string]validjsonator.Schema{ bodyParam.Name: schema, }, } @@ -246,7 +247,7 @@ func Generate(filePath string) astra.ServiceFunction { s.Log.Debug().Msg("Added paths") components := Components{ - Schemas: make(map[string]Schema), + Schemas: make(map[string]validjsonator.Schema), } s.Log.Debug().Msg("Adding components") diff --git a/outputs/openapi/schema.go b/outputs/openapi/schema.go index 8417b96..fe6a7c0 100644 --- a/outputs/openapi/schema.go +++ b/outputs/openapi/schema.go @@ -3,9 +3,10 @@ package openapi import ( "github.com/ls6-events/astra" "github.com/ls6-events/astra/astTraversal" + "github.com/ls6-events/validjsonator" ) -func mapParamToSchema(bindingType astTraversal.BindingTagType, param astra.Param) (Schema, bool) { +func mapParamToSchema(bindingType astTraversal.BindingTagType, param astra.Param) (validjsonator.Schema, bool) { if param.IsBound { return mapFieldToSchema(bindingType, param.Field) } else if param.IsArray { @@ -13,17 +14,17 @@ func mapParamToSchema(bindingType astTraversal.BindingTagType, param astra.Param if !astra.IsAcceptedType(param.Field.Type) { componentRef, bound := makeComponentRef(bindingType, param.Field.Type, param.Field.Package) if bound { - itemSchema = Schema{ + itemSchema = validjsonator.Schema{ Ref: componentRef, } } } - return Schema{ + return validjsonator.Schema{ Type: "array", Items: &itemSchema, }, true } else if param.IsMap { - var additionalProperties Schema + var additionalProperties validjsonator.Schema if !astra.IsAcceptedType(param.Field.Type) { componentRef, bound := makeComponentRef(bindingType, param.Field.Type, param.Field.Package) if bound { @@ -32,7 +33,7 @@ func mapParamToSchema(bindingType astTraversal.BindingTagType, param astra.Param } else { additionalProperties = mapPredefinedTypeFormat(param.Field.Type) } - return Schema{ + return validjsonator.Schema{ Type: "object", AdditionalProperties: &additionalProperties, }, true @@ -41,33 +42,33 @@ func mapParamToSchema(bindingType astTraversal.BindingTagType, param astra.Param } } -func mapFieldToSchema(bindingType astTraversal.BindingTagType, field astra.Field) (Schema, bool) { +func mapFieldToSchema(bindingType astTraversal.BindingTagType, field astra.Field) (validjsonator.Schema, bool) { if !astra.IsAcceptedType(field.Type) { componentRef, bound := makeComponentRef(bindingType, field.Type, field.Package) if bound { - return Schema{ + return validjsonator.Schema{ Ref: componentRef, }, true } - return Schema{}, false + return validjsonator.Schema{}, false } else { schema := mapPredefinedTypeFormat(field.Type) if field.Type == "slice" { - itemSchema := Schema{ + itemSchema := validjsonator.Schema{ Type: mapPredefinedTypeFormat(field.SliceType).Type, } if !astra.IsAcceptedType(field.SliceType) { componentRef, bound := makeComponentRef(bindingType, field.SliceType, field.Package) if bound { - itemSchema = Schema{ + itemSchema = validjsonator.Schema{ Ref: componentRef, } } } schema.Items = &itemSchema } else if field.Type == "map" { - var additionalProperties Schema + var additionalProperties validjsonator.Schema if !astra.IsAcceptedType(field.MapValueType) { componentRef, bound := makeComponentRef(bindingType, field.MapValueType, field.Package) if bound { @@ -85,38 +86,38 @@ func mapFieldToSchema(bindingType astTraversal.BindingTagType, field astra.Field // mapTypeFormat maps the type with the list of types from the service. // This should be primarily used for custom types in components that need to be mapped. -func mapTypeFormat(service *astra.Service, acceptedType string, pkg string) Schema { +func mapTypeFormat(service *astra.Service, acceptedType string, pkg string) validjsonator.Schema { if acceptedType, ok := service.GetTypeMapping(acceptedType, pkg); ok { if acceptedType.Type == "" { - return Schema{} + return validjsonator.Schema{} } - return Schema{ + return validjsonator.Schema{ Type: acceptedType.Type, Format: acceptedType.Format, } } - return Schema{} + return validjsonator.Schema{} } // mapPredefinedTypeFormat maps the type with the list of types that are predefined. // This should be primarily used for types that are not custom types, i.e. everywhere except top level components. -func mapPredefinedTypeFormat(acceptedType string) Schema { +func mapPredefinedTypeFormat(acceptedType string) validjsonator.Schema { if acceptedType, ok := astra.PredefinedTypeMap[acceptedType]; ok { if acceptedType.Type == "" { - return Schema{} + return validjsonator.Schema{} } - return Schema{ + return validjsonator.Schema{ Type: acceptedType.Type, Format: acceptedType.Format, } } - return Schema{} + return validjsonator.Schema{} } // getQueryParamStyle returns the style of the query parameter, based on the schema. -func getQueryParamStyle(schema Schema) (style string, explode bool) { +func getQueryParamStyle(schema validjsonator.Schema) (style string, explode bool) { if schema.Type == "object" { return "deepObject", true } diff --git a/outputs/openapi/schema_test.go b/outputs/openapi/schema_test.go index e6a1a72..195ee94 100644 --- a/outputs/openapi/schema_test.go +++ b/outputs/openapi/schema_test.go @@ -1,13 +1,14 @@ package openapi import ( + "github.com/ls6-events/validjsonator" "github.com/stretchr/testify/require" "testing" ) func TestGetQueryParamStyle(t *testing.T) { t.Run("it returns the correct style for object types", func(t *testing.T) { - style, explode := getQueryParamStyle(Schema{ + style, explode := getQueryParamStyle(validjsonator.Schema{ Type: "object", }) @@ -17,7 +18,7 @@ func TestGetQueryParamStyle(t *testing.T) { t.Run("it returns the correct style for a primitives or array types", func(t *testing.T) { t.Run("string", func(t *testing.T) { - style, explode := getQueryParamStyle(Schema{ + style, explode := getQueryParamStyle(validjsonator.Schema{ Type: "string", }) @@ -27,7 +28,7 @@ func TestGetQueryParamStyle(t *testing.T) { }) t.Run("int", func(t *testing.T) { - style, explode := getQueryParamStyle(Schema{ + style, explode := getQueryParamStyle(validjsonator.Schema{ Type: "int", }) @@ -36,7 +37,7 @@ func TestGetQueryParamStyle(t *testing.T) { }) t.Run("array", func(t *testing.T) { - style, explode := getQueryParamStyle(Schema{ + style, explode := getQueryParamStyle(validjsonator.Schema{ Type: "array", }) diff --git a/outputs/openapi/types.go b/outputs/openapi/types.go index 3ec78d1..580d512 100644 --- a/outputs/openapi/types.go +++ b/outputs/openapi/types.go @@ -1,5 +1,7 @@ package openapi +import "github.com/ls6-events/validjsonator" + // OpenAPISchema is the OpenAPI schema. type OpenAPISchema struct { OpenAPI string `json:"openapi" yaml:"openapi"` @@ -81,16 +83,16 @@ type Operation struct { // Parameter is the OpenAPI parameter. type Parameter struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - In string `json:"in,omitempty" yaml:"in,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Required bool `json:"required,omitempty" yaml:"required,omitempty"` - Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` - AllowEmpty bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` - Style string `json:"style,omitempty" yaml:"style,omitempty"` - Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"` - Schema Schema `json:"schema,omitempty" yaml:"schema,omitempty"` + Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Required bool `json:"required,omitempty" yaml:"required,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + AllowEmpty bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` + Style string `json:"style,omitempty" yaml:"style,omitempty"` + Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"` + Schema validjsonator.Schema `json:"schema,omitempty" yaml:"schema,omitempty"` } // RequestBody is the OpenAPI request body. @@ -103,8 +105,8 @@ type RequestBody struct { // MediaType is the OpenAPI media type. type MediaType struct { - Schema Schema `json:"schema,omitempty" yaml:"schema,omitempty"` - Encoding map[string]Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"` + Schema validjsonator.Schema `json:"schema,omitempty" yaml:"schema,omitempty"` + Encoding map[string]Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"` } // Encoding is the OpenAPI encoding. @@ -115,12 +117,12 @@ type Encoding struct { // Header is the OpenAPI header. type Header struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Required bool `json:"required,omitempty" yaml:"required,omitempty"` - Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` - AllowEmpty bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` - Schema Schema `json:"schema,omitempty" yaml:"schema,omitempty"` + Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Required bool `json:"required,omitempty" yaml:"required,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + AllowEmpty bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"` + Schema validjsonator.Schema `json:"schema,omitempty" yaml:"schema,omitempty"` } // Responses is the OpenAPI responses. @@ -152,47 +154,15 @@ type Callback map[string]Path // Components is the OpenAPI components. type Components struct { - Schemas map[string]Schema `json:"schemas,omitempty" yaml:"schemas,omitempty"` - Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` - Parameters map[string]Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` - RequestBodies map[string]RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"` - Headers map[string]Header `json:"headers,omitempty" yaml:"headers,omitempty"` - SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"` - Links map[string]Link `json:"links,omitempty" yaml:"links,omitempty"` - Callbacks map[string]Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` - PathItems map[string]Path `json:"pathItems,omitempty" yaml:"pathItems,omitempty"` -} - -// Schema is JSON Schema utilised by OpenAPI. -type Schema struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Title string `json:"title,omitempty" yaml:"title,omitempty"` - MultipleOf float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` - Maximum float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` - ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` - Minimum float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` - ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` - MaxLength int `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` - MinLength int `json:"minLength,omitempty" yaml:"minLength,omitempty"` - Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` - MaxItems int `json:"maxItems,omitempty" yaml:"maxItems,omitempty"` - MinItems int `json:"minItems,omitempty" yaml:"minItems,omitempty"` - UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"` - MaxProperties int `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"` - MinProperties int `json:"minProperties,omitempty" yaml:"minProperties,omitempty"` - Required []string `json:"required,omitempty" yaml:"required,omitempty"` - Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` - Format string `json:"format,omitempty" yaml:"format,omitempty"` - AllOf []Schema `json:"allOf,omitempty" yaml:"allOf,omitempty"` - OneOf []Schema `json:"oneOf,omitempty" yaml:"oneOf,omitempty"` - AnyOf []Schema `json:"anyOf,omitempty" yaml:"anyOf,omitempty"` - Not *Schema `json:"not,omitempty" yaml:"not,omitempty"` - Items *Schema `json:"items,omitempty" yaml:"items,omitempty"` - Properties map[string]Schema `json:"properties,omitempty" yaml:"properties,omitempty"` - PatternProperties map[string]Schema `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"` - AdditionalProperties *Schema `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` + Schemas map[string]validjsonator.Schema `json:"schemas,omitempty" yaml:"schemas,omitempty"` + Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` + Parameters map[string]Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + RequestBodies map[string]RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"` + Headers map[string]Header `json:"headers,omitempty" yaml:"headers,omitempty"` + SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"` + Links map[string]Link `json:"links,omitempty" yaml:"links,omitempty"` + Callbacks map[string]Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` + PathItems map[string]Path `json:"pathItems,omitempty" yaml:"pathItems,omitempty"` } // SecurityScheme is the OpenAPI security scheme. diff --git a/tests/integration/0-template/components_test.go b/tests/integration/0-template/components_test.go index 49f2c1d..5b82f95 100644 --- a/tests/integration/0-template/components_test.go +++ b/tests/integration/0-template/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/0-template/config_test.go b/tests/integration/0-template/config_test.go index c8974f5..8819076 100644 --- a/tests/integration/0-template/config_test.go +++ b/tests/integration/0-template/config_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/0-template/handlers.go b/tests/integration/0-template/handlers.go index 32b28b8..ca073e7 100644 --- a/tests/integration/0-template/handlers.go +++ b/tests/integration/0-template/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -16,13 +15,13 @@ func getAllPets(c *gin.Context) { } func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -50,13 +49,13 @@ func createPet(c *gin.Context) { } func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/0-template/paths_test.go b/tests/integration/0-template/paths_test.go index 343cd32..dbbcfec 100644 --- a/tests/integration/0-template/paths_test.go +++ b/tests/integration/0-template/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/0-template/router.go b/tests/integration/0-template/router.go index 0a73435..abe6cef 100644 --- a/tests/integration/0-template/router.go +++ b/tests/integration/0-template/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/1-basic/components_test.go b/tests/integration/1-basic/components_test.go index 7a67f40..ae1e2ed 100644 --- a/tests/integration/1-basic/components_test.go +++ b/tests/integration/1-basic/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" @@ -27,7 +27,7 @@ func TestSchemas(t *testing.T) { // petstore.Pet require.True(t, schemas.Exists("petstore.Pet")) require.Equal(t, "object", schemas.Search("petstore.Pet", "type").Data().(string)) - require.Equal(t, "integer", schemas.Search("petstore.Pet", "properties", "id", "type").Data().(string)) + require.Equal(t, "string", schemas.Search("petstore.Pet", "properties", "id", "type").Data().(string)) require.Equal(t, "string", schemas.Search("petstore.Pet", "properties", "name", "type").Data().(string)) require.Equal(t, "array", schemas.Search("petstore.Pet", "properties", "photoUrls", "type").Data().(string)) require.Equal(t, "string", schemas.Search("petstore.Pet", "properties", "photoUrls", "items", "type").Data().(string)) @@ -48,6 +48,6 @@ func TestSchemas(t *testing.T) { // petstore.Tag require.True(t, schemas.Exists("petstore.Tag")) require.Equal(t, "object", schemas.Search("petstore.Tag", "type").Data().(string)) - require.Equal(t, "integer", schemas.Search("petstore.Tag", "properties", "id", "type").Data().(string)) + require.Equal(t, "string", schemas.Search("petstore.Tag", "properties", "id", "type").Data().(string)) require.Equal(t, "string", schemas.Search("petstore.Tag", "properties", "name", "type").Data().(string)) } diff --git a/tests/integration/1-basic/config_test.go b/tests/integration/1-basic/config_test.go index 5ca1a31..cba4e03 100644 --- a/tests/integration/1-basic/config_test.go +++ b/tests/integration/1-basic/config_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra" diff --git a/tests/integration/1-basic/handlers.go b/tests/integration/1-basic/handlers.go index 32b28b8..ca073e7 100644 --- a/tests/integration/1-basic/handlers.go +++ b/tests/integration/1-basic/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -16,13 +15,13 @@ func getAllPets(c *gin.Context) { } func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -50,13 +49,13 @@ func createPet(c *gin.Context) { } func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/1-basic/paths_test.go b/tests/integration/1-basic/paths_test.go index 07c7c19..ac69164 100644 --- a/tests/integration/1-basic/paths_test.go +++ b/tests/integration/1-basic/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/1-basic/router.go b/tests/integration/1-basic/router.go index 0a73435..abe6cef 100644 --- a/tests/integration/1-basic/router.go +++ b/tests/integration/1-basic/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/10-struct-name-collision-avoidance/components_test.go b/tests/integration/10-struct-name-collision-avoidance/components_test.go index a5f68f5..db572d6 100644 --- a/tests/integration/10-struct-name-collision-avoidance/components_test.go +++ b/tests/integration/10-struct-name-collision-avoidance/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/10-struct-name-collision-avoidance/handlers.go b/tests/integration/10-struct-name-collision-avoidance/handlers.go index 1d0de28..8a0abb6 100644 --- a/tests/integration/10-struct-name-collision-avoidance/handlers.go +++ b/tests/integration/10-struct-name-collision-avoidance/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "net/http" diff --git a/tests/integration/10-struct-name-collision-avoidance/router.go b/tests/integration/10-struct-name-collision-avoidance/router.go index 2b9c942..b7fb630 100644 --- a/tests/integration/10-struct-name-collision-avoidance/router.go +++ b/tests/integration/10-struct-name-collision-avoidance/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/11-multi-content-types/components_test.go b/tests/integration/11-multi-content-types/components_test.go index 759650b..4a22a6e 100644 --- a/tests/integration/11-multi-content-types/components_test.go +++ b/tests/integration/11-multi-content-types/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/11-multi-content-types/handlers.go b/tests/integration/11-multi-content-types/handlers.go index 0a7df22..cefb05e 100644 --- a/tests/integration/11-multi-content-types/handlers.go +++ b/tests/integration/11-multi-content-types/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/gin-gonic/gin" diff --git a/tests/integration/11-multi-content-types/router.go b/tests/integration/11-multi-content-types/router.go index a1e0610..03f5baf 100644 --- a/tests/integration/11-multi-content-types/router.go +++ b/tests/integration/11-multi-content-types/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/12-substitute-types/components_test.go b/tests/integration/12-substitute-types/components_test.go index e5973b8..bd835ca 100644 --- a/tests/integration/12-substitute-types/components_test.go +++ b/tests/integration/12-substitute-types/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra" diff --git a/tests/integration/12-substitute-types/handlers.go b/tests/integration/12-substitute-types/handlers.go index 32b28b8..ca073e7 100644 --- a/tests/integration/12-substitute-types/handlers.go +++ b/tests/integration/12-substitute-types/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -16,13 +15,13 @@ func getAllPets(c *gin.Context) { } func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -50,13 +49,13 @@ func createPet(c *gin.Context) { } func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/12-substitute-types/router.go b/tests/integration/12-substitute-types/router.go index 0a73435..abe6cef 100644 --- a/tests/integration/12-substitute-types/router.go +++ b/tests/integration/12-substitute-types/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/14-file-uploads/handlers.go b/tests/integration/14-file-uploads/handlers.go index 9b337f8..e9e47f1 100644 --- a/tests/integration/14-file-uploads/handlers.go +++ b/tests/integration/14-file-uploads/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "net/http" diff --git a/tests/integration/14-file-uploads/paths_test.go b/tests/integration/14-file-uploads/paths_test.go index ab236b6..5021484 100644 --- a/tests/integration/14-file-uploads/paths_test.go +++ b/tests/integration/14-file-uploads/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/14-file-uploads/router.go b/tests/integration/14-file-uploads/router.go index 2e312c8..faa79bc 100644 --- a/tests/integration/14-file-uploads/router.go +++ b/tests/integration/14-file-uploads/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/15-bound-query-params/handlers.go b/tests/integration/15-bound-query-params/handlers.go index a257c3c..6ffe1b6 100644 --- a/tests/integration/15-bound-query-params/handlers.go +++ b/tests/integration/15-bound-query-params/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "net/http" diff --git a/tests/integration/15-bound-query-params/paths_test.go b/tests/integration/15-bound-query-params/paths_test.go index 6835a48..8ef75ae 100644 --- a/tests/integration/15-bound-query-params/paths_test.go +++ b/tests/integration/15-bound-query-params/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/15-bound-query-params/router.go b/tests/integration/15-bound-query-params/router.go index a8e4811..d076412 100644 --- a/tests/integration/15-bound-query-params/router.go +++ b/tests/integration/15-bound-query-params/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/16-struct-validation/.gitignore b/tests/integration/16-struct-validation/.gitignore new file mode 100644 index 0000000..325a564 --- /dev/null +++ b/tests/integration/16-struct-validation/.gitignore @@ -0,0 +1 @@ +output.json \ No newline at end of file diff --git a/tests/integration/16-struct-validation/README.md b/tests/integration/16-struct-validation/README.md new file mode 100644 index 0000000..5a2bdd1 --- /dev/null +++ b/tests/integration/16-struct-validation/README.md @@ -0,0 +1,2 @@ +# 16 Struct Validation +This test is used to test the extraction of struct validation in the Astra service. \ No newline at end of file diff --git a/tests/integration/16-struct-validation/components_test.go b/tests/integration/16-struct-validation/components_test.go new file mode 100644 index 0000000..467b82d --- /dev/null +++ b/tests/integration/16-struct-validation/components_test.go @@ -0,0 +1,37 @@ +package integration + +import ( + "github.com/ls6-events/astra/tests/integration/helpers" + "github.com/stretchr/testify/require" + "testing" +) + +func TestSchemas(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + + r := setupRouter() + + testAstra, err := helpers.SetupTestAstraWithDefaultConfig(t, r) + require.NoError(t, err) + + components := testAstra.Path("components") + + schemas := components.Path("schemas") + + // Pet + require.True(t, schemas.Exists("petstore.Pet")) + require.ElementsMatch(t, []interface{}{"id", "name"}, schemas.Search("petstore.Pet", "required").Data().([]interface{})) + require.Equal(t, map[string]interface{}{"id": map[string]interface{}{"allOf": []interface{}{map[string]interface{}{"format": "uuid"}}, "type": "string"}, "name": map[string]interface{}{"type": "string"}, "photoUrls": map[string]interface{}{"allOf": []interface{}{map[string]interface{}{}}, "items": map[string]interface{}{"type": "string", "allOf": []interface{}{map[string]interface{}{"format": "uri"}}}, "type": "array"}, "status": map[string]interface{}{"type": "string"}, "tags": map[string]interface{}{"items": map[string]interface{}{"$ref": "#/components/schemas/petstore.Tag"}, "type": "array"}}, schemas.Search("petstore.Pet", "properties").Data().(map[string]interface{})) + + // PetDTO + require.True(t, schemas.Exists("petstore.PetDTO")) + require.ElementsMatch(t, []interface{}{"name"}, schemas.Search("petstore.PetDTO", "required").Data().([]interface{})) + require.Equal(t, map[string]interface{}{"name": map[string]interface{}{"type": "string"}, "photoUrls": map[string]interface{}{"allOf": []interface{}{map[string]interface{}{}}, "items": map[string]interface{}{"type": "string", "allOf": []interface{}{map[string]interface{}{"format": "uri"}}}, "type": "array"}, "status": map[string]interface{}{"type": "string"}, "tags": map[string]interface{}{"items": map[string]interface{}{"$ref": "#/components/schemas/petstore.Tag"}, "type": "array"}}, schemas.Search("petstore.PetDTO", "properties").Data().(map[string]interface{})) + + // Tag + require.True(t, schemas.Exists("petstore.Tag")) + require.ElementsMatch(t, []interface{}{"id", "name"}, schemas.Search("petstore.Tag", "required").Data().([]interface{})) + require.Equal(t, map[string]interface{}{"id": map[string]interface{}{"allOf": []interface{}{map[string]interface{}{"format": "uuid"}}, "type": "string"}, "name": map[string]interface{}{"type": "string"}}, schemas.Search("petstore.Tag", "properties").Data().(map[string]interface{})) +} diff --git a/tests/integration/16-struct-validation/handlers.go b/tests/integration/16-struct-validation/handlers.go new file mode 100644 index 0000000..ca073e7 --- /dev/null +++ b/tests/integration/16-struct-validation/handlers.go @@ -0,0 +1,61 @@ +package integration + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/ls6-events/astra/tests/petstore" +) + +func getAllPets(c *gin.Context) { + allPets := petstore.Pets + + c.JSON(http.StatusOK, allPets) +} + +func getPetByID(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) + return + } + + pet, err := petstore.PetByID(id) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, pet) +} + +func createPet(c *gin.Context) { + var pet petstore.PetDTO + err := c.BindJSON(&pet) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + petstore.AddPet(petstore.Pet{ + Name: pet.Name, + PhotoURLs: pet.PhotoURLs, + Status: pet.Status, + Tags: pet.Tags, + }) + + c.JSON(http.StatusOK, pet) +} + +func deletePet(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) + return + } + + petstore.RemovePet(id) + + c.Status(http.StatusOK) +} diff --git a/tests/integration/16-struct-validation/router.go b/tests/integration/16-struct-validation/router.go new file mode 100644 index 0000000..abe6cef --- /dev/null +++ b/tests/integration/16-struct-validation/router.go @@ -0,0 +1,14 @@ +package integration + +import "github.com/gin-gonic/gin" + +func setupRouter() *gin.Engine { + r := gin.Default() + + r.GET("/pets", getAllPets) + r.GET("/pets/:id", getPetByID) + r.POST("/pets", createPet) + r.DELETE("/pets/:id", deletePet) + + return r +} diff --git a/tests/integration/2-struct-embedding/components_test.go b/tests/integration/2-struct-embedding/components_test.go index 88c378c..674709c 100644 --- a/tests/integration/2-struct-embedding/components_test.go +++ b/tests/integration/2-struct-embedding/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/2-struct-embedding/handlers.go b/tests/integration/2-struct-embedding/handlers.go index 1923ef9..6e9dec2 100644 --- a/tests/integration/2-struct-embedding/handlers.go +++ b/tests/integration/2-struct-embedding/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -10,13 +9,13 @@ import ( ) func getCatByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -30,13 +29,13 @@ func getCatByID(c *gin.Context) { } func getDogByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return diff --git a/tests/integration/2-struct-embedding/paths_test.go b/tests/integration/2-struct-embedding/paths_test.go index 3c013f7..df713b3 100644 --- a/tests/integration/2-struct-embedding/paths_test.go +++ b/tests/integration/2-struct-embedding/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/2-struct-embedding/router.go b/tests/integration/2-struct-embedding/router.go index 1c29c62..b294d2c 100644 --- a/tests/integration/2-struct-embedding/router.go +++ b/tests/integration/2-struct-embedding/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/2-struct-embedding/types.go b/tests/integration/2-struct-embedding/types.go index a72f12c..e94ca07 100644 --- a/tests/integration/2-struct-embedding/types.go +++ b/tests/integration/2-struct-embedding/types.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/petstore" diff --git a/tests/integration/3-inline-functions/paths_test.go b/tests/integration/3-inline-functions/paths_test.go index 9bbca7d..2cd2ee4 100644 --- a/tests/integration/3-inline-functions/paths_test.go +++ b/tests/integration/3-inline-functions/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/3-inline-functions/router.go b/tests/integration/3-inline-functions/router.go index 570ebdc..08554f4 100644 --- a/tests/integration/3-inline-functions/router.go +++ b/tests/integration/3-inline-functions/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/gin-gonic/gin" diff --git a/tests/integration/4-doc-comments/components_test.go b/tests/integration/4-doc-comments/components_test.go index 510aec6..5672b3d 100644 --- a/tests/integration/4-doc-comments/components_test.go +++ b/tests/integration/4-doc-comments/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/4-doc-comments/handlers.go b/tests/integration/4-doc-comments/handlers.go index 7abf5e1..c61267d 100644 --- a/tests/integration/4-doc-comments/handlers.go +++ b/tests/integration/4-doc-comments/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -19,13 +18,13 @@ func getAllPets(c *gin.Context) { // getPetByID returns a pet by its ID. // It takes in the ID as a path parameter. func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -57,13 +56,13 @@ func createPet(c *gin.Context) { // deletePet deletes a pet by its ID. // It takes in the ID as a path parameter. func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/4-doc-comments/paths_test.go b/tests/integration/4-doc-comments/paths_test.go index 3800808..9ba9038 100644 --- a/tests/integration/4-doc-comments/paths_test.go +++ b/tests/integration/4-doc-comments/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/4-doc-comments/router.go b/tests/integration/4-doc-comments/router.go index 93a7d11..95ea627 100644 --- a/tests/integration/4-doc-comments/router.go +++ b/tests/integration/4-doc-comments/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/5-custom-functions/customFunctions.go b/tests/integration/5-custom-functions/customFunctions.go index 6eeff1d..3f015e5 100644 --- a/tests/integration/5-custom-functions/customFunctions.go +++ b/tests/integration/5-custom-functions/customFunctions.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/5-custom-functions/handlers.go b/tests/integration/5-custom-functions/handlers.go index 819ee54..384c2f0 100644 --- a/tests/integration/5-custom-functions/handlers.go +++ b/tests/integration/5-custom-functions/handlers.go @@ -1,14 +1,16 @@ -package petstore +package integration import ( + "errors" "net/http" - "strconv" "github.com/gin-gonic/gin" "github.com/ls6-events/astra/tests/petstore" ) +var ErrIDRequired = errors.New("ID is required") + // getAllPets returns all pets. func getAllPets(c *gin.Context) { allPets := petstore.Pets @@ -19,13 +21,13 @@ func getAllPets(c *gin.Context) { // getPetByID returns a pet by its ID. // It takes in the ID as a path parameter. func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - handleError(c, http.StatusBadRequest, err) + id := c.Param("id") + if id == "" { + handleError(c, http.StatusBadRequest, ErrIDRequired) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { handleError(c, http.StatusNotFound, err) return @@ -57,13 +59,13 @@ func createPet(c *gin.Context) { // deletePet deletes a pet by its ID. // It takes in the ID as a path parameter. func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - handleError(c, http.StatusBadRequest, err) + id := c.Param("id") + if id == "" { + handleError(c, http.StatusBadRequest, ErrIDRequired) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/5-custom-functions/paths_test.go b/tests/integration/5-custom-functions/paths_test.go index 0885335..e3ca55b 100644 --- a/tests/integration/5-custom-functions/paths_test.go +++ b/tests/integration/5-custom-functions/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra" diff --git a/tests/integration/5-custom-functions/router.go b/tests/integration/5-custom-functions/router.go index 0a73435..abe6cef 100644 --- a/tests/integration/5-custom-functions/router.go +++ b/tests/integration/5-custom-functions/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/6-openapi-format/components_test.go b/tests/integration/6-openapi-format/components_test.go index d926544..4a91788 100644 --- a/tests/integration/6-openapi-format/components_test.go +++ b/tests/integration/6-openapi-format/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/6-openapi-format/router.go b/tests/integration/6-openapi-format/router.go index 124ac9b..7d872c3 100644 --- a/tests/integration/6-openapi-format/router.go +++ b/tests/integration/6-openapi-format/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/6-openapi-format/type.go b/tests/integration/6-openapi-format/type.go index 7368488..5b6effa 100644 --- a/tests/integration/6-openapi-format/type.go +++ b/tests/integration/6-openapi-format/type.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "time" diff --git a/tests/integration/7-enums/components_test.go b/tests/integration/7-enums/components_test.go index 97dc941..41c5491 100644 --- a/tests/integration/7-enums/components_test.go +++ b/tests/integration/7-enums/components_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/7-enums/enum.go b/tests/integration/7-enums/enum.go index 6c7b7d1..55a896a 100644 --- a/tests/integration/7-enums/enum.go +++ b/tests/integration/7-enums/enum.go @@ -1,4 +1,4 @@ -package petstore +package integration type TestStringEnum string diff --git a/tests/integration/7-enums/handlers.go b/tests/integration/7-enums/handlers.go index 46cc5a9..53abd16 100644 --- a/tests/integration/7-enums/handlers.go +++ b/tests/integration/7-enums/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "net/http" diff --git a/tests/integration/7-enums/router.go b/tests/integration/7-enums/router.go index b43cb2f..1f0970d 100644 --- a/tests/integration/7-enums/router.go +++ b/tests/integration/7-enums/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/8-headers-abort/handlers.go b/tests/integration/8-headers-abort/handlers.go index a5d94a2..2dd5f6c 100644 --- a/tests/integration/8-headers-abort/handlers.go +++ b/tests/integration/8-headers-abort/handlers.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "net/http" diff --git a/tests/integration/8-headers-abort/paths_test.go b/tests/integration/8-headers-abort/paths_test.go index 2d40db6..137d500 100644 --- a/tests/integration/8-headers-abort/paths_test.go +++ b/tests/integration/8-headers-abort/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/8-headers-abort/router.go b/tests/integration/8-headers-abort/router.go index 040365d..b1c0b7b 100644 --- a/tests/integration/8-headers-abort/router.go +++ b/tests/integration/8-headers-abort/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/integration/9-operation-ids/handlers.go b/tests/integration/9-operation-ids/handlers.go index 32b28b8..ca073e7 100644 --- a/tests/integration/9-operation-ids/handlers.go +++ b/tests/integration/9-operation-ids/handlers.go @@ -1,8 +1,7 @@ -package petstore +package integration import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -16,13 +15,13 @@ func getAllPets(c *gin.Context) { } func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -50,13 +49,13 @@ func createPet(c *gin.Context) { } func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/integration/9-operation-ids/paths_test.go b/tests/integration/9-operation-ids/paths_test.go index 2d286ce..909b212 100644 --- a/tests/integration/9-operation-ids/paths_test.go +++ b/tests/integration/9-operation-ids/paths_test.go @@ -1,4 +1,4 @@ -package petstore +package integration import ( "github.com/ls6-events/astra/tests/integration/helpers" diff --git a/tests/integration/9-operation-ids/router.go b/tests/integration/9-operation-ids/router.go index 0a73435..abe6cef 100644 --- a/tests/integration/9-operation-ids/router.go +++ b/tests/integration/9-operation-ids/router.go @@ -1,4 +1,4 @@ -package petstore +package integration import "github.com/gin-gonic/gin" diff --git a/tests/petstore/store.go b/tests/petstore/store.go index efe160e..f7ed8a9 100644 --- a/tests/petstore/store.go +++ b/tests/petstore/store.go @@ -3,19 +3,19 @@ package petstore import ( "fmt" "sync" - "sync/atomic" + + "github.com/google/uuid" ) var Pets = []Pet{ - {ID: 1, Name: "Dog", PhotoURLs: []string{}, Status: "available", Tags: nil}, - {ID: 2, Name: "Cat", PhotoURLs: []string{}, Status: "pending", Tags: nil}, + {ID: "a0652c3a-142f-438a-a553-381a7c135d9b", Name: "Dog", PhotoURLs: []string{}, Status: "available", Tags: nil}, + {ID: "95188ede-b9ab-44ba-95b1-71b5d5c31f7f", Name: "Cat", PhotoURLs: []string{}, Status: "pending", Tags: nil}, } var petsLock = &sync.Mutex{} -var lastPetID int64 = 2 -func newPetID() int64 { - return atomic.AddInt64(&lastPetID, 1) +func newPetID() string { + return uuid.New().String() } func AddPet(pet Pet) { @@ -25,7 +25,7 @@ func AddPet(pet Pet) { Pets = append(Pets, pet) } -func RemovePet(id int64) { +func RemovePet(id string) { petsLock.Lock() defer petsLock.Unlock() var newPets []Pet @@ -37,11 +37,11 @@ func RemovePet(id int64) { Pets = newPets } -func PetByID(id int64) (*Pet, error) { +func PetByID(id string) (*Pet, error) { for _, pet := range Pets { if pet.ID == id { return &pet, nil } } - return nil, fmt.Errorf("not found: pet %d", id) + return nil, fmt.Errorf("not found: pet %s", id) } diff --git a/tests/petstore/types.go b/tests/petstore/types.go index 2896b3c..ffadd3c 100644 --- a/tests/petstore/types.go +++ b/tests/petstore/types.go @@ -2,23 +2,23 @@ package petstore // Tag the tag model. type Tag struct { - ID int64 `json:"id"` - Name string `json:"name"` + ID string `json:"id" binding:"required,uuid4"` + Name string `json:"name" binding:"required"` } // Pet the pet model. type Pet struct { - ID int64 `json:"id"` - Name string `json:"name"` - PhotoURLs []string `json:"photoUrls,omitempty"` + ID string `json:"id" binding:"required,uuid4"` + Name string `json:"name" binding:"required"` + PhotoURLs []string `json:"photoUrls,omitempty" binding:"dive,url"` Status string `json:"status,omitempty"` Tags []Tag `json:"tags,omitempty"` } // PetDTO the pet dto. type PetDTO struct { - Name string `json:"name"` - PhotoURLs []string `json:"photoUrls,omitempty"` + Name string `json:"name" binding:"required"` + PhotoURLs []string `json:"photoUrls,omitempty" binding:"dive,url"` Status string `json:"status,omitempty"` Tags []Tag `json:"tags,omitempty"` } diff --git a/tests/snapshot/petstore/handlers.go b/tests/snapshot/petstore/handlers.go index a3a7df8..4701d2e 100644 --- a/tests/snapshot/petstore/handlers.go +++ b/tests/snapshot/petstore/handlers.go @@ -2,7 +2,6 @@ package snapshot import ( "net/http" - "strconv" "github.com/gin-gonic/gin" @@ -16,13 +15,13 @@ func getAllPets(c *gin.Context) { } func getPetByID(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - pet, err := petstore.PetByID(int64(id)) + pet, err := petstore.PetByID(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return @@ -50,13 +49,13 @@ func createPet(c *gin.Context) { } func deletePet(c *gin.Context) { - id, err := strconv.Atoi(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"}) return } - petstore.RemovePet(int64(id)) + petstore.RemovePet(id) c.Status(http.StatusOK) } diff --git a/tests/snapshot/petstore/snapshot.yaml b/tests/snapshot/petstore/snapshot.yaml index efac17c..54c4362 100644 --- a/tests/snapshot/petstore/snapshot.yaml +++ b/tests/snapshot/petstore/snapshot.yaml @@ -96,20 +96,27 @@ components: type: object properties: id: - type: integer - format: int64 + type: string + allOf: + - format: uuid name: type: string photoUrls: type: array items: type: string + allOf: + - format: uri + allOf: [{}] status: type: string tags: type: array items: $ref: '#/components/schemas/petstore.Tag' + required: + - id + - name description: Pet the pet model. petstore.PetDTO: type: object @@ -120,19 +127,28 @@ components: type: array items: type: string + allOf: + - format: uri + allOf: [{}] status: type: string tags: type: array items: $ref: '#/components/schemas/petstore.Tag' + required: + - name description: PetDTO the pet dto. petstore.Tag: type: object properties: id: - type: integer - format: int64 + type: string + allOf: + - format: uuid name: type: string + required: + - id + - name description: Tag the tag model. diff --git a/types.go b/types.go index 48deddd..238deec 100644 --- a/types.go +++ b/types.go @@ -86,9 +86,10 @@ type Field struct { MapKeyType string `json:"mapKeyType,omitempty" yaml:"mapKeyType,omitempty"` MapValueType string `json:"mapValueType,omitempty" yaml:"mapValueType,omitempty"` - StructFields map[string]Field `json:"structFields,omitempty" yaml:"structFields,omitempty"` - StructFieldBindingTags astTraversal.BindingTagMap `json:"structFieldBindingTags,omitempty" yaml:"structFieldBindingTags,omitempty"` - StructFieldValidationTags astTraversal.ValidationTagMap `json:"structFieldValidationTags,omitempty" yaml:"structFieldValidationTags,omitempty"` + StructFields map[string]Field `json:"structFields,omitempty" yaml:"structFields,omitempty"` + StructFieldBindingTags astTraversal.BindingTagMap `json:"structFieldBindingTags,omitempty" yaml:"structFieldBindingTags,omitempty"` + StructFieldValidationTags astTraversal.ValidationTagMap `json:"structFieldValidationTags,omitempty" yaml:"structFieldValidationTags,omitempty"` + StructFieldValidationRequired astTraversal.ValidationRequiredMap `json:"structFieldValidationRequired,omitempty" yaml:"structFieldValidationRequired,omitempty"` Doc string `json:"doc,omitempty" yaml:"doc,omitempty"` } diff --git a/utils.go b/utils.go index adaaa9b..1257c15 100644 --- a/utils.go +++ b/utils.go @@ -9,17 +9,18 @@ import ( // ParseResultToField changes a result from the AST traversal to a local field. func ParseResultToField(result astTraversal.Result) Field { field := Field{ - Type: result.Type, - Name: result.Name, - EnumValues: result.EnumValues, - IsEmbedded: result.IsEmbedded, - SliceType: result.SliceType, - ArrayType: result.ArrayType, - ArrayLength: result.ArrayLength, - MapKeyType: result.MapKeyType, - MapValueType: result.MapValueType, - StructFieldBindingTags: result.StructFieldBindingTags, - StructFieldValidationTags: result.StructFieldValidationTags, + Type: result.Type, + Name: result.Name, + EnumValues: result.EnumValues, + IsEmbedded: result.IsEmbedded, + SliceType: result.SliceType, + ArrayType: result.ArrayType, + ArrayLength: result.ArrayLength, + MapKeyType: result.MapKeyType, + MapValueType: result.MapValueType, + StructFieldBindingTags: result.StructFieldBindingTags, + StructFieldValidationTags: result.StructFieldValidationTags, + StructFieldValidationRequired: result.StructFieldValidationRequired, } // If the godoc is populated, we need to parse the response.