Skip to content

Commit 59eebd7

Browse files
authored
Merge branch 'master' into master
2 parents 6fa5676 + 6321ee8 commit 59eebd7

File tree

6 files changed

+129
-7
lines changed

6 files changed

+129
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Here's some projects that depend on _kin-openapi_:
2121
* [github.com/a-h/rest](https://github.com/a-h/rest) - "Generate OpenAPI 3.0 specifications from Go code without annotations or magic comments"
2222
* [github.com/Tufin/oasdiff](https://github.com/Tufin/oasdiff) - "A diff tool for OpenAPI Specification 3"
2323
* [github.com/danielgtaylor/apisprout](https://github.com/danielgtaylor/apisprout) - "Lightweight, blazing fast, cross-platform OpenAPI 3 mock server with validation"
24-
* [github.com/deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) - "Generate Go client and server boilerplate from OpenAPI 3 specifications"
24+
* [github.com/oapi-codegen/oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) - "Generate Go client and server boilerplate from OpenAPI 3 specifications"
2525
* [github.com/dunglas/vulcain](https://github.com/dunglas/vulcain) - "Use HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs"
2626
* [github.com/danielgtaylor/restish](https://github.com/danielgtaylor/restish) - "...a CLI for interacting with REST-ish HTTP APIs with some nice features built-in"
2727
* [github.com/goadesign/goa](https://github.com/goadesign/goa) - "Design-based APIs and microservices in Go"

openapi2conv/openapi2_conv.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,14 @@ func convertRefsInV3SchemaRef(from *openapi3.SchemaRef) *openapi3.SchemaRef {
568568
to.Value.Items.Ref = ToV3Ref(to.Value.Items.Ref)
569569
}
570570
to.Value.AdditionalProperties = toV3AdditionalProperties(to.Value.AdditionalProperties)
571+
572+
if len(to.Value.AllOf) > 0 {
573+
allOf := make(openapi3.SchemaRefs, len(to.Value.AllOf))
574+
for i, schemaRef := range to.Value.AllOf {
575+
allOf[i] = convertRefsInV3SchemaRef(schemaRef)
576+
}
577+
to.Value.AllOf = allOf
578+
}
571579
}
572580
return &to
573581
}

openapi2conv/openapi2_conv_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,87 @@ func TestConvOpenAPIV2ToV3WithNestedAdditionalPropertiesSchemaRef(t *testing.T)
193193
require.Equal(t, "#/components/schemas/Foo", responseSchema.AdditionalProperties.Schema.Value.AdditionalProperties.Schema.Ref)
194194
}
195195

196+
func TestConvOpenAPIV2ToV3WithAllOfInsideAdditionalProperties(t *testing.T) {
197+
v2 := []byte(`
198+
{
199+
"basePath": "/v2",
200+
"host": "test.example.com",
201+
"info": {
202+
"title": "MyAPI",
203+
"version": "0.1"
204+
},
205+
"paths": {
206+
"/v1/objStatus": {
207+
"get": {
208+
"produces": [
209+
"application/json"
210+
],
211+
"responses": {
212+
"200": {
213+
"schema": {
214+
"type": "object",
215+
"properties": {
216+
"result": {
217+
"type": "object",
218+
"additionalProperties": {
219+
"type": "object",
220+
"allOf": [
221+
{
222+
"$ref": "#/definitions/ObjectInfo"
223+
}
224+
],
225+
"additionalProperties": {
226+
"allOf": [
227+
{
228+
"$ref": "#/definitions/ObjectInfo"
229+
}
230+
]
231+
}
232+
}
233+
}
234+
}
235+
},
236+
"description": "Success"
237+
}
238+
}
239+
}
240+
}
241+
},
242+
"definitions": {
243+
"ObjectInfo": {
244+
"type": "object",
245+
"properties": {
246+
"object_id": {
247+
"type": "string",
248+
"format": "uuid"
249+
}
250+
}
251+
}
252+
},
253+
"schemes": [
254+
"http"
255+
],
256+
"swagger": "2.0"
257+
}
258+
`)
259+
260+
var doc2 openapi2.T
261+
err := json.Unmarshal(v2, &doc2)
262+
require.NoError(t, err)
263+
264+
doc3, err := ToV3(&doc2)
265+
require.NoError(t, err)
266+
err = doc3.Validate(context.Background())
267+
require.NoError(t, err)
268+
269+
responseSchema := doc3.Paths.Value("/v1/objStatus").Get.Responses.Value("200").Value.Content.Get("application/json").Schema.Value
270+
require.Equal(t, &openapi3.Types{"object"}, responseSchema.Type)
271+
resultSchema := responseSchema.Properties["result"].Value
272+
require.Equal(t, &openapi3.Types{"object"}, resultSchema.Type)
273+
require.Equal(t, "#/components/schemas/ObjectInfo", resultSchema.AdditionalProperties.Schema.Value.AllOf[0].Ref)
274+
require.Equal(t, "#/components/schemas/ObjectInfo", resultSchema.AdditionalProperties.Schema.Value.AdditionalProperties.Schema.Value.AllOf[0].Ref)
275+
}
276+
196277
const exampleV2 = `
197278
{
198279
"basePath": "/v2",

openapi3filter/req_resp_decoder.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,12 @@ func (d *urlValuesDecoder) parseArray(raw []string, sm *openapi3.SerializationMe
565565
}
566566
value = append(value, item)
567567
}
568+
// If the array has only one element and that element is an empty string, it means no value exists, so return nil.
569+
if len(value) == 1 {
570+
if str, ok := value[0].(string); ok && str == "" {
571+
return nil, nil
572+
}
573+
}
568574
return value, nil
569575
}
570576

@@ -1116,13 +1122,13 @@ func parseArray(raw []string, schemaRef *openapi3.SchemaRef) ([]any, error) {
11161122
}
11171123

11181124
// parsePrimitive returns a value that is created by parsing a source string to a primitive type
1119-
// that is specified by a schema. The function returns nil when the source string is empty.
1125+
// that is specified by a schema. The function returns nil when the source string is empty and the type is not "string".
11201126
// The function panics when a schema has a non-primitive type.
11211127
func parsePrimitive(raw string, schema *openapi3.SchemaRef) (v any, err error) {
1122-
if raw == "" {
1123-
return nil, nil
1124-
}
11251128
for _, typ := range schema.Value.Type.Slice() {
1129+
if raw == "" && typ != "string" {
1130+
return nil, nil
1131+
}
11261132
if v, err = parsePrimitiveCase(raw, schema, typ); err == nil {
11271133
return
11281134
}

openapi3filter/req_resp_decoder_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,13 +671,27 @@ func TestDecodeParameter(t *testing.T) {
671671
want: "foo",
672672
found: true,
673673
},
674+
{
675+
name: "string empty",
676+
param: &openapi3.Parameter{Name: "param", In: "query", Schema: stringSchema},
677+
query: "param=",
678+
want: "",
679+
found: true,
680+
},
674681
{
675682
name: "integer",
676683
param: &openapi3.Parameter{Name: "param", In: "query", Schema: integerSchema},
677684
query: "param=1",
678685
want: int64(1),
679686
found: true,
680687
},
688+
{
689+
name: "integer empty",
690+
param: &openapi3.Parameter{Name: "param", In: "query", Schema: integerSchema},
691+
query: "param=",
692+
want: nil,
693+
found: true,
694+
},
681695
{
682696
name: "integer invalid",
683697
param: &openapi3.Parameter{Name: "param", In: "query", Schema: integerSchema},
@@ -692,6 +706,13 @@ func TestDecodeParameter(t *testing.T) {
692706
want: 1.1,
693707
found: true,
694708
},
709+
{
710+
name: "number empty",
711+
param: &openapi3.Parameter{Name: "param", In: "query", Schema: numberSchema},
712+
query: "param=",
713+
want: nil,
714+
found: true,
715+
},
695716
{
696717
name: "number invalid",
697718
param: &openapi3.Parameter{Name: "param", In: "query", Schema: numberSchema},
@@ -706,6 +727,13 @@ func TestDecodeParameter(t *testing.T) {
706727
want: true,
707728
found: true,
708729
},
730+
{
731+
name: "boolean empty",
732+
param: &openapi3.Parameter{Name: "param", In: "query", Schema: booleanSchema},
733+
query: "param=",
734+
want: nil,
735+
found: true,
736+
},
709737
{
710738
name: "boolean invalid",
711739
param: &openapi3.Parameter{Name: "param", In: "query", Schema: booleanSchema},

openapi3filter/validate_response_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ func Test_validateResponseHeader(t *testing.T) {
4242
},
4343
isHeaderPresent: true,
4444
headerVals: []string{""},
45-
wantErr: true,
46-
wantErrMsg: `response header "X-Blab" doesn't match schema: Value is not nullable`,
45+
wantErr: false,
4746
},
4847
{
4948
name: "test optional string header with single string value",

0 commit comments

Comments
 (0)