Skip to content

Commit

Permalink
test(issue-238): validate header parameter is set in openapi spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Zaba505 committed Aug 19, 2024
1 parent dc7fa8c commit fc98b11
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
5 changes: 5 additions & 0 deletions rest/endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ func Headers(hs ...Header) Option {
In: openapi3.ParameterInHeader,
Name: h.Name,
Required: ptr.Ref(h.Required),
Schema: &openapi3.SchemaOrRef{
Schema: &openapi3.Schema{
Type: ptr.Ref(openapi3.SchemaTypeString),
},
},
})

o.validators = append(o.validators, validateHeader(h))
Expand Down
36 changes: 36 additions & 0 deletions rest/endpoint/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
func setOpenApiSpec(o *options) func(*openapi3.Spec) {
return compose(
addSchemas(o.schemas),
addHeaders(o.method, o.pattern, o.headers...),
addRequestBody(o.method, o.pattern, o.request),
addResponses(o.method, o.pattern, o.responses),
)
Expand Down Expand Up @@ -53,6 +54,41 @@ func addSchemas(schemas map[string]*openapi3.Schema) func(*openapi3.Spec) {
}
}

func addHeaders(method, pattern string, headers ...*openapi3.Parameter) func(*openapi3.Spec) {
return func(s *openapi3.Spec) {
if len(headers) == 0 {
return
}

if s.Paths.MapOfPathItemValues == nil {
s.Paths.MapOfPathItemValues = make(map[string]openapi3.PathItem)
}

pathItemVals := s.Paths.MapOfPathItemValues
pathItem, ok := pathItemVals[pattern]
if !ok {
pathItem = openapi3.PathItem{
MapOfOperationValues: make(map[string]openapi3.Operation),
}
}

opVals := pathItem.MapOfOperationValues
opVal, ok := opVals[method]
if !ok {
opVal = openapi3.Operation{}
}

for _, h := range headers {
opVal.Parameters = append(opVal.Parameters, openapi3.ParameterOrRef{
Parameter: h,
})
}

opVals[method] = opVal
pathItemVals[pattern] = pathItem
}
}

func addRequestBody(method, pattern string, reqBody *openapi3.RequestBody) func(*openapi3.Spec) {
return func(s *openapi3.Spec) {
if reqBody == nil {
Expand Down
146 changes: 146 additions & 0 deletions rest/endpoint/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,157 @@ import (
"strings"
"testing"

"github.com/z5labs/bedrock/pkg/ptr"

"github.com/stretchr/testify/assert"
"github.com/swaggest/openapi-go/openapi3"
)

func TestEndpoint_OpenApi(t *testing.T) {
t.Run("will set non-required header parameter", func(t *testing.T) {
t.Run("if a header is provided with the Headers option", func(t *testing.T) {
method := strings.ToLower(http.MethodPost)
pattern := "/"
header := Header{
Name: "MyHeader",
Required: true,
}

e := New(
method,
pattern,
HandlerFunc[Empty, Empty](func(_ context.Context, _ Empty) (Empty, error) {
return Empty{}, nil
}),
Headers(header),
)

refSpec := &openapi3.Spec{
Openapi: "3.0.3",
}
e.OpenApi(refSpec)

b, err := json.Marshal(refSpec)
if !assert.Nil(t, err) {
return
}

var spec openapi3.Spec
err = json.Unmarshal(b, &spec)
if !assert.Nil(t, err) {
return
}

pathItems := spec.Paths.MapOfPathItemValues
if !assert.Len(t, pathItems, 1) {
return
}
if !assert.Contains(t, pathItems, pattern) {
return
}

ops := pathItems[pattern].MapOfOperationValues
if !assert.Len(t, ops, 1) {
return
}
if !assert.Contains(t, ops, method) {
return
}

op := ops[method]
params := op.Parameters
if !assert.Len(t, params, 1) {
return
}

param := params[0].Parameter
if !assert.NotNil(t, param) {
return
}
if !assert.Equal(t, openapi3.ParameterInHeader, param.In) {
return
}
if !assert.Equal(t, header.Name, param.Name) {
return
}
if !assert.Equal(t, header.Required, ptr.Deref(param.Required)) {
return
}
})
})

t.Run("will set required header parameter", func(t *testing.T) {
t.Run("if a header is provided with the Headers option", func(t *testing.T) {
method := strings.ToLower(http.MethodPost)
pattern := "/"
header := Header{
Name: "MyHeader",
Required: true,
}

e := New(
method,
pattern,
HandlerFunc[Empty, Empty](func(_ context.Context, _ Empty) (Empty, error) {
return Empty{}, nil
}),
Headers(header),
)

refSpec := &openapi3.Spec{
Openapi: "3.0.3",
}
e.OpenApi(refSpec)

b, err := json.Marshal(refSpec)
if !assert.Nil(t, err) {
return
}

var spec openapi3.Spec
err = json.Unmarshal(b, &spec)
if !assert.Nil(t, err) {
return
}

pathItems := spec.Paths.MapOfPathItemValues
if !assert.Len(t, pathItems, 1) {
return
}
if !assert.Contains(t, pathItems, pattern) {
return
}

ops := pathItems[pattern].MapOfOperationValues
if !assert.Len(t, ops, 1) {
return
}
if !assert.Contains(t, ops, method) {
return
}

op := ops[method]
params := op.Parameters
if !assert.Len(t, params, 1) {
return
}

param := params[0].Parameter
if !assert.NotNil(t, param) {
return
}
if !assert.Equal(t, openapi3.ParameterInHeader, param.In) {
return
}
if !assert.Equal(t, header.Name, param.Name) {
return
}
if !assert.Equal(t, header.Required, ptr.Deref(param.Required)) {
return
}
})
})

t.Run("will set request body type", func(t *testing.T) {
t.Run("if the request type implements ContentTyper interface", func(t *testing.T) {
method := strings.ToLower(http.MethodPost)
Expand Down

0 comments on commit fc98b11

Please sign in to comment.