Skip to content

Commit

Permalink
OpenAPI: parses the 'validate' struct tag
Browse files Browse the repository at this point in the history
  • Loading branch information
EwenQuim committed Mar 6, 2024
1 parent a38f745 commit dd7253d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 2 deletions.
2 changes: 1 addition & 1 deletion examples/full-app-gourmet/controller/ingredient.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (rs ingredientRessource) getAllIngredients(c fuego.ContextNoBody) ([]store.
}

type CreateIngredient struct {
Name string `json:"name" validate:"required,min=3,max=20"`
Name string `json:"name" validate:"required,min=3,max=20" example:"Tomato"`
Description string `json:"description"`
}

Expand Down
5 changes: 5 additions & 0 deletions openapi3/openapi3.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,14 @@ type Schema struct {
Type string `json:"type,omitempty" yaml:"type"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
Nullable bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
Example string `json:"example,omitempty" yaml:"example,omitempty"`
Properties map[string]Schema `json:"properties,omitempty" yaml:"properties,omitempty"`
Items *Schema `json:"items,omitempty" yaml:"items,omitempty"`
MinLength int `json:"minLength,omitempty" yaml:"minLength,omitempty"`
MaxLength int `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
Minimum int `json:"minimum,omitempty" yaml:"minimum,omitempty"`
Maximum int `json:"maximum,omitempty" yaml:"maximum,omitempty"`
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
}

Expand Down
29 changes: 29 additions & 0 deletions openapi3/parse_validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package openapi3

import (
"strconv"
"strings"
)

// parses the "validate" tag used by go-playground/validator and sets the schema accordingly
func parseValidate(s *Schema, tag string) {
for _, item := range strings.Split(tag, ",") {
if strings.Contains(item, "min=") {
min := strings.Split(item, "min=")[1]
if s.Type == "integer" || s.Type == "number" {
s.Minimum, _ = strconv.Atoi(min)
} else if s.Type == "string" {
s.MinLength, _ = strconv.Atoi(min)
}
}

if strings.Contains(item, "max=") {
max := strings.Split(item, "max=")[1]
if s.Type == "integer" || s.Type == "number" {
s.Maximum, _ = strconv.Atoi(max)
} else if s.Type == "string" {
s.MaxLength, _ = strconv.Atoi(max)
}
}
}
}
62 changes: 62 additions & 0 deletions openapi3/parse_validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package openapi3

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestParseValidate(t *testing.T) {
t.Run("empty", func(t *testing.T) {
s := &Schema{}
parseValidate(s, "")
})

t.Run("required", func(t *testing.T) {
t.Skip("TODO")
s := &Schema{}
parseValidate(s, "required")
require.Equal(t, true, s.Required)
})

t.Run("min for int", func(t *testing.T) {
s := &Schema{
Type: "integer",
}
parseValidate(s, "min=10")
require.Equal(t, 10, s.Minimum)
})

t.Run("max for int", func(t *testing.T) {
s := &Schema{
Type: "integer",
}
parseValidate(s, "max=10")
require.Equal(t, 10, s.Maximum)
})

t.Run("min for string", func(t *testing.T) {
s := &Schema{
Type: "string",
}
parseValidate(s, "min=10")
require.Equal(t, 10, s.MinLength)
})

t.Run("max for string", func(t *testing.T) {
s := &Schema{
Type: "string",
}
parseValidate(s, "max=10")
require.Equal(t, 10, s.MaxLength)
})

t.Run("multiple", func(t *testing.T) {
s := &Schema{
Type: "string",
}
parseValidate(s, "required,min=10,max=20")
require.Equal(t, 10, s.MinLength)
require.Equal(t, 20, s.MaxLength)
})
}
6 changes: 5 additions & 1 deletion openapi3/to_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,15 @@ func ToSchema(v any) *Schema {
if strings.Contains(fieldType.Tag.Get("validate"), "required") {
s.Required = append(s.Required, fieldName)
}
s.Properties[fieldName] = Schema{

fieldSchema := Schema{
Type: fieldTypeType,
Example: fieldType.Tag.Get("example"),
Format: format,
}
parseValidate(&fieldSchema, fieldType.Tag.Get("validate"))
s.Properties[fieldName] = fieldSchema

}
}
}
Expand Down

0 comments on commit dd7253d

Please sign in to comment.