diff --git a/go.mod b/go.mod index 6fda630..1baa50b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/gin-gonic/gin v1.7.4 github.com/labstack/echo/v4 v4.6.1 - github.com/miketonks/swag v0.0.0-20211006155010-b4fa61e72278 // indirect + github.com/miketonks/swag v0.0.0-20211006155010-b4fa61e72278 github.com/stretchr/testify v1.7.0 github.com/xeipuuv/gojsonschema v1.2.0 ) diff --git a/swag-validator.go b/swag-validator.go index ec9f196..084d28e 100644 --- a/swag-validator.go +++ b/swag-validator.go @@ -580,6 +580,38 @@ func buildRequestSchema(e *swagger.Endpoint) *RequestSchema { return &r } +func convertProperty(p swagger.Property) SchemaProperty { + sp := SchemaProperty{ + Description: p.Description, + Enum: p.Enum, + Format: p.Format, + Ref: p.Ref, + Example: p.Example, + Items: p.Items, + Pattern: p.Pattern, + MinItems: p.MinItems, + MaxItems: p.MaxItems, + UniqueItems: p.UniqueItems, + MinLength: p.MinLength, + MaxLength: p.MaxLength, + Minimum: p.Minimum, + Maximum: p.Maximum, + ExclusiveMinimum: p.ExclusiveMinimum, + ExclusiveMaximum: p.ExclusiveMaximum, + AdditionalProperties: p.AdditionalProperties, + } + if p.Type != "" { + sp.Type = strings.Split(p.Type, ",") + } + if p.Nullable { + sp.Type = append(sp.Type, "null") + } + if prop, ok := p.AdditionalProperties.(*swagger.Property); ok { + sp.AdditionalProperties = convertProperty(*prop) + } + return sp +} + func buildSchemaDefinitions(api *swagger.API) map[string]SchemaDefinition { defs := map[string]SchemaDefinition{} for _, d := range api.Definitions { @@ -592,31 +624,7 @@ func buildSchemaDefinitions(api *swagger.API) map[string]SchemaDefinition { AdditionalProperties: d.AdditionalProperties, } for k, p := range d.Properties { - sp := SchemaProperty{ - Description: p.Description, - Enum: p.Enum, - Format: p.Format, - Ref: p.Ref, - Example: p.Example, - Items: p.Items, - Pattern: p.Pattern, - MinItems: p.MinItems, - MaxItems: p.MaxItems, - UniqueItems: p.UniqueItems, - MinLength: p.MinLength, - MaxLength: p.MaxLength, - Minimum: p.Minimum, - Maximum: p.Maximum, - ExclusiveMinimum: p.ExclusiveMinimum, - ExclusiveMaximum: p.ExclusiveMaximum, - AdditionalProperties: p.AdditionalProperties, - } - if p.Type != "" { - sp.Type = strings.Split(p.Type, ",") - } - if p.Nullable { - sp.Type = append(sp.Type, "null") - } + sp := convertProperty(p) schemaDef.Properties[k] = sp } diff --git a/swag-validator_echo_test.go b/swag-validator_echo_test.go index d4b9b5f..5b97e3c 100644 --- a/swag-validator_echo_test.go +++ b/swag-validator_echo_test.go @@ -213,7 +213,7 @@ func TestPayloadEcho(t *testing.T) { testTable := []struct { description string - in payload + in interface{} expectedStatus int expectedResponse map[string]interface{} }{ @@ -457,6 +457,25 @@ func TestPayloadEcho(t *testing.T) { expectedStatus: 200, expectedResponse: nil, }, + { + description: "Non-nullable map has no null elems, nullable has both null and non-null elems", + in: map[string]interface{}{ + "non_null_elems": map[string]*string{"foo": pString("bar")}, + "nullable_elems": map[string]*string{"foo": pString("bar"), "baz": nil}, + }, + expectedStatus: 200, + expectedResponse: nil, + }, + { + description: "Non-nullable map has null elems", + in: map[string]interface{}{ + "non_null_elems": map[string]*string{"foo": nil}, + }, + expectedStatus: 400, + expectedResponse: map[string]interface{}{ + "non_null_elems.foo": "Invalid type. Expected: string, given: null", + }, + }, } api := swag.New(swag.Endpoints(endpoint.New("POST", "/validate-test", "Test the validator", @@ -484,6 +503,10 @@ func TestPayloadEcho(t *testing.T) { } } +func pString(s string) *string { + return &s +} + func TestOptionsReturnErrorsEcho(t *testing.T) { api := swag.New( diff --git a/swag-validator_gin_test.go b/swag-validator_gin_test.go index 891f671..5bb3ec2 100644 --- a/swag-validator_gin_test.go +++ b/swag-validator_gin_test.go @@ -220,7 +220,7 @@ func TestPayloadGin(t *testing.T) { testTable := []struct { description string - in payload + in interface{} expectedStatus int expectedResponse map[string]interface{} }{ @@ -464,6 +464,25 @@ func TestPayloadGin(t *testing.T) { expectedStatus: 200, expectedResponse: nil, }, + { + description: "Non-nullable map has no null elems, nullable has both null and non-null elems", + in: map[string]interface{}{ + "non_null_elems": map[string]*string{"foo": pString("bar")}, + "nullable_elems": map[string]*string{"foo": pString("bar"), "baz": nil}, + }, + expectedStatus: 200, + expectedResponse: nil, + }, + { + description: "Non-nullable map has null elems", + in: map[string]interface{}{ + "non_null_elems": map[string]*string{"foo": nil}, + }, + expectedStatus: 400, + expectedResponse: map[string]interface{}{ + "non_null_elems.foo": "Invalid type. Expected: string, given: null", + }, + }, } api := swag.New(swag.Endpoints(endpoint.New("POST", "/validate-test", "Test the validator", diff --git a/swag-validator_test.go b/swag-validator_test.go index 615b047..61afb85 100644 --- a/swag-validator_test.go +++ b/swag-validator_test.go @@ -38,9 +38,12 @@ type payload struct { MaxItemsArr []string `json:"max_items_arr,omitempty" max_items:"3"` MinItemsArr []string `json:"min_items_arr,omitempty" min_items:"2"` UniqueItemsAarr []string `json:"unique_items_arr,omitempty" unique_items:"true"` + + NonNullElems map[string]string `json:"non_null_elems,omitempty"` + NullableElems map[string]*string `json:"nullable_elems,omitempty"` } -func preparePostRequest(url string, body payload) *http.Request { +func preparePostRequest(url string, body interface{}) *http.Request { buff, err := json.Marshal(body) if err != nil { log.Fatalf("Failed to marshal the body: %s", err)