diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index a476a9f96b..4e429e08ec 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -2,6 +2,8 @@ package codegen import ( "fmt" + "regexp" + "sort" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -13,10 +15,14 @@ type Schema struct { GoType string // The Go type needed to represent the schema RefType string // If the type has a type name, this is set + IsExternal bool // Whether it was defined externally, i.e. "x-go-type" + Validations Validations + ArrayType *Schema // The schema of array element EnumValues map[string]string // Enum values + EmbeddedFields []string // For an allOf struct Properties []Property // For an object, the fields with names HasAdditionalProperties bool // Whether we support additional properties AdditionalPropertiesType *Schema // And if we do, their type @@ -27,6 +33,30 @@ type Schema struct { Description string // The description of the element } +// Validations describes validations for a schema. +type Validations struct { + // String + MinLength uint64 + MaxLength *uint64 + Pattern string + Values []string + + // Number + Min *float64 + ExclusiveMin bool + Max *float64 + ExclusiveMax bool + MultipleOf *float64 + + // Array + MinItems uint64 + MaxItems *uint64 + + // Additional Properties + MinProps uint64 + MaxProps *uint64 +} + func (s Schema) IsRef() bool { return s.RefType != "" } @@ -194,6 +224,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return outSchema, errors.Wrapf(err, "invalid value for %q", extPropGoType) } outSchema.GoType = typeName + outSchema.IsExternal = true return outSchema, nil } @@ -269,6 +300,9 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return Schema{}, errors.Wrap(err, "error generating type for additional properties") } outSchema.AdditionalPropertiesType = &additionalSchema + // Validation rules: + outSchema.Validations.MinProps = schema.MinProps + outSchema.Validations.MaxProps = schema.MaxProps } outSchema.GoType = GenStructFromSchema(outSchema) @@ -306,6 +340,12 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { outSchema.RefType = typeName } //outSchema.RefType = typeName + + outSchema.Validations.Values = make([]string, 0, len(outSchema.EnumValues)) + for _, value := range outSchema.EnumValues { + outSchema.Validations.Values = append(outSchema.Validations.Values, value) + } + sort.Sort(sort.StringSlice(outSchema.Validations.Values)) } else { err := resolveType(schema, path, &outSchema) if err != nil { @@ -336,6 +376,8 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro outSchema.AdditionalTypes = append(outSchema.AdditionalTypes, additionalTypes...) } outSchema.Properties = arrayType.Properties + outSchema.Validations.MinItems = schema.MinItems + outSchema.Validations.MaxItems = schema.MaxItems case "integer": // We default to int if format doesn't ask for something else. if f == "int64" { @@ -351,6 +393,11 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro } else { return fmt.Errorf("invalid integer format: %s", f) } + outSchema.Validations.Min = schema.Min + outSchema.Validations.ExclusiveMin = schema.ExclusiveMin + outSchema.Validations.Max = schema.Max + outSchema.Validations.ExclusiveMax = schema.ExclusiveMax + outSchema.Validations.MultipleOf = schema.MultipleOf case "number": // We default to float for "number" if f == "double" { @@ -360,6 +407,8 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro } else { return fmt.Errorf("invalid number format: %s", f) } + outSchema.Validations.Min = schema.Min + outSchema.Validations.Max = schema.Max case "boolean": if f != "" { return fmt.Errorf("invalid format (%s) for boolean", f) @@ -382,6 +431,14 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro default: // All unrecognized formats are simply a regular string. outSchema.GoType = "string" + outSchema.Validations.MinLength = schema.MinLength + outSchema.Validations.MaxLength = schema.MaxLength + if schema.Pattern != "" { + // Try to compile it first + if _, err := regexp.Compile(schema.Pattern); err == nil { + outSchema.Validations.Pattern = schema.Pattern + } + } } default: return fmt.Errorf("unhandled Schema type: %s", t) @@ -468,6 +525,7 @@ func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { if err != nil { return Schema{}, errors.Wrap(err, "error converting reference path to a go type") } + outSchema.EmbeddedFields = append(outSchema.EmbeddedFields, refType) } schema, err := GenerateGoSchema(schemaOrRef, path)