Skip to content

Commit

Permalink
openapi3: add missing document parameter validations (#835)
Browse files Browse the repository at this point in the history
  • Loading branch information
radwaretaltr authored Sep 5, 2023
1 parent 4f6515e commit b58fbe3
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 12 deletions.
7 changes: 6 additions & 1 deletion openapi3/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (header *Header) Validate(ctx context.Context, opts ...ValidationOption) er
return fmt.Errorf("header schema is invalid: %w", e)
}

if (header.Schema == nil) == (header.Content == nil) {
if (header.Schema == nil) == (len(header.Content) == 0) {
e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", header)
return fmt.Errorf("header schema is invalid: %w", e)
}
Expand All @@ -100,6 +100,11 @@ func (header *Header) Validate(ctx context.Context, opts ...ValidationOption) er
}

if content := header.Content; content != nil {
e := errors.New("parameter content must only contain one entry")
if len(content) > 1 {
return fmt.Errorf("header content is invalid: %w", e)
}

if err := content.Validate(ctx); err != nil {
return fmt.Errorf("header content is invalid: %w", err)
}
Expand Down
7 changes: 6 additions & 1 deletion openapi3/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,17 @@ func (parameter *Parameter) Validate(ctx context.Context, opts ...ValidationOpti
return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e)
}

if (parameter.Schema == nil) == (parameter.Content == nil) {
if (parameter.Schema == nil) == (len(parameter.Content) == 0) {
e := errors.New("parameter must contain exactly one of content and schema")
return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e)
}

if content := parameter.Content; content != nil {
e := errors.New("parameter content must only contain one entry")
if len(content) > 1 {
return fmt.Errorf("parameter %q content is invalid: %w", parameter.Name, e)
}

if err := content.Validate(ctx); err != nil {
return fmt.Errorf("parameter %q content is invalid: %w", parameter.Name, err)
}
Expand Down
114 changes: 114 additions & 0 deletions openapi3/parameter_issue834_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package openapi3

import (
"context"
"testing"

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

func TestPathItemParametersAreValidated(t *testing.T) {
spec := []byte(`
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
parameters:
- in: invalid
name: test
schema:
type: string
get:
summary: List all pets
operationId: listPets
tags:
- pets
responses:
'200':
description: A paged array of pets
`[1:])

loader := NewLoader()
doc, err := loader.LoadFromData(spec)
require.NoError(t, err)
err = doc.Validate(context.Background())
require.EqualError(t, err, `invalid paths: invalid path /pets: parameter can't have 'in' value "invalid"`)
}

func TestParameterMultipleContentEntries(t *testing.T) {
spec := []byte(`
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
parameters:
- in: query
name: test
content:
application/json:
schema:
type: string
application/xml:
schema:
type: string
get:
summary: List all pets
operationId: listPets
tags:
- pets
responses:
'200':
description: A paged array of pets
`[1:])

loader := NewLoader()
doc, err := loader.LoadFromData(spec)
require.NoError(t, err)
err = doc.Validate(context.Background())
require.EqualError(t, err, `invalid paths: invalid path /pets: parameter "test" content is invalid: parameter content must only contain one entry`)
}

func TestParameterEmptyContent(t *testing.T) {
spec := []byte(`
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
parameters:
- in: query
name: test
content: {}
get:
summary: List all pets
operationId: listPets
tags:
- pets
responses:
'200':
description: A paged array of pets
`[1:])

loader := NewLoader()
doc, err := loader.LoadFromData(spec)
require.NoError(t, err)
err = doc.Validate(context.Background())
require.EqualError(t, err, `invalid paths: invalid path /pets: parameter "test" schema is invalid: parameter must contain exactly one of content and schema`)
}
6 changes: 6 additions & 0 deletions openapi3/path_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,5 +207,11 @@ func (pathItem *PathItem) Validate(ctx context.Context, opts ...ValidationOption
}
}

if v := pathItem.Parameters; v != nil {
if err := v.Validate(ctx); err != nil {
return err
}
}

return validateExtensions(ctx, pathItem.Extensions)
}
10 changes: 5 additions & 5 deletions routers/gorillamux/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,21 @@ func TestRouter(t *testing.T) {
"/params/{x}/{y}/{z:.*}": &openapi3.PathItem{
Get: paramsGET,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("x")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("y")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("z")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("x").WithSchema(openapi3.NewStringSchema())},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("y").WithSchema(openapi3.NewFloat64Schema())},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("z").WithSchema(openapi3.NewIntegerSchema())},
},
},
"/books/{bookid}": &openapi3.PathItem{
Get: paramsGET,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid").WithSchema(openapi3.NewStringSchema())},
},
},
"/books/{bookid}.json": &openapi3.PathItem{
Post: booksPOST,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid2").WithSchema(openapi3.NewStringSchema())},
},
},
"/partial": &openapi3.PathItem{
Expand Down
10 changes: 5 additions & 5 deletions routers/legacy/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,21 @@ func TestRouter(t *testing.T) {
"/params/{x}/{y}/{z.*}": &openapi3.PathItem{
Get: paramsGET,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("x")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("y")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("z")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("x").WithSchema(openapi3.NewStringSchema())},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("y").WithSchema(openapi3.NewFloat64Schema())},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("z").WithSchema(openapi3.NewIntegerSchema())},
},
},
"/books/{bookid}": &openapi3.PathItem{
Get: paramsGET,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid").WithSchema(openapi3.NewStringSchema())},
},
},
"/books/{bookid2}.json": &openapi3.PathItem{
Post: booksPOST,
Parameters: openapi3.Parameters{
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid2")},
&openapi3.ParameterRef{Value: openapi3.NewPathParameter("bookid2").WithSchema(openapi3.NewStringSchema())},
},
},
"/partial": &openapi3.PathItem{
Expand Down

0 comments on commit b58fbe3

Please sign in to comment.