nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: getkin/kin-openapi
Pull request #58 (2019-01-18 17:23:12)

Fix typo in swagger v2 schemes
There was a typo in the json field name which prevented the parser from loading schemes properly.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields


Patch:
diff --git a/openapi2/openapi2.go b/openapi2/openapi2.go
index 231f3c9..3fdd8a1 100644
--- a/openapi2/openapi2.go
+++ b/openapi2/openapi2.go
@@ -16,7 +16,7 @@ import (
 type Swagger struct {
 	Info                openapi3.Info                  `json:"info"`
 	ExternalDocs        *openapi3.ExternalDocs         `json:"externalDocs,omitempty"`
-	Schemes             []string                       `json:"schemas,omitempty"`
+	Schemes             []string                       `json:"schemes,omitempty"`
 	Host                string                         `json:"host,omitempty"`
 	BasePath            string                         `json:"basePath,omitempty"`
 	Paths               map[string]*PathItem           `json:"paths,omitempty"`


Test patch:
diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go
index 81fc176..1265792 100644
--- a/openapi2conv/openapi2_conv_test.go
+++ b/openapi2conv/openapi2_conv_test.go
@@ -37,7 +37,7 @@ func TestConvOpenAPIV2ToV3(t *testing.T) {
 const exampleV2 = `
 {
   "info": {},
-  "schemas": ["https"],
+  "schemes": ["https"],
   "host": "test.example.com",
   "basePath": "/v2",
   "paths": {
Repository: getkin/kin-openapi
Pull request #74 (2019-03-19 18:06:28)

Add support for RFC 3339 time-secfrac to the date-time regex
Per the RFC 3339 spec, a date-time may contain an optional time-secfrac for fractional seconds: https://tools.ietf.org/html/rfc3339#section-5.6.

Add support for that case and update the tests.


Patch:
diff --git a/openapi3/schema_formats.go b/openapi3/schema_formats.go
index 43d1996..aa7df87 100644
--- a/openapi3/schema_formats.go
+++ b/openapi3/schema_formats.go
@@ -29,5 +29,5 @@ func init() {
 	DefineStringFormat("date", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`)
 
 	// date-time
-	DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
+	DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
 }


Test patch:
diff --git a/openapi3/schema_test.go b/openapi3/schema_test.go
index f8b610a..8980c34 100644
--- a/openapi3/schema_test.go
+++ b/openapi3/schema_test.go
@@ -248,12 +248,16 @@ var schemaExamples = []schemaExample{
 			"2017-12-31T11:59:59Z",
 			"2017-12-31T11:59:59-11:30",
 			"2017-12-31T11:59:59+11:30",
+			"2017-12-31T11:59:59.999+11:30",
+			"2017-12-31T11:59:59.999Z",
 		},
 		AllInvalid: []interface{}{
 			nil,
 			3.14,
 			"2017-12-31",
 			"2017-12-31T11:59:59\n",
+			"2017-12-31T11:59:59.+11:30",
+			"2017-12-31T11:59:59.Z",
 		},
 	},
Repository: getkin/kin-openapi
Pull request #94 (2019-05-13 19:21:46)

Support missing mime types in validation
When a mime type is missing, rather than present and invalid, we return
the */* match as the request is not invalid for refusing to send a mime
type.

The RFC defining content-type states that including is a `SHOULD` rather than a `MUST`.

kconwayatlassian: @fenollp I found another edge case in the request/response validation. In this case, it is technically valid for a request or response to _not_ contain the content-type header. This is a case that my team has encountered where we'd like to still apply validation but the current version considers an empty string to be equal to an invalid mime type.

Patch:
diff --git a/openapi3/content.go b/openapi3/content.go
index 941c032..8d187fd 100644
--- a/openapi3/content.go
+++ b/openapi3/content.go
@@ -24,6 +24,12 @@ func NewContentWithJSONSchemaRef(schema *SchemaRef) Content {
 }
 
 func (content Content) Get(mime string) *MediaType {
+	// If the mime is empty then short-circuit to the wildcard.
+	// We do this here so that we catch only the specific case of
+	// and empty mime rather than a present, but invalid, mime type.
+	if mime == "" {
+		return content["*/*"]
+	}
 	// Start by making the most specific match possible
 	// by using the mime type in full.
 	if v := content[mime]; v != nil {


Test patch:
diff --git a/openapi3/content_test.go b/openapi3/content_test.go
index 4dff3a7..8b132a7 100644
--- a/openapi3/content_test.go
+++ b/openapi3/content_test.go
@@ -93,6 +93,12 @@ func TestContent_Get(t *testing.T) {
 			mime:    "text",
 			want:    nil,
 		},
+		{
+			name:    "missing mime type",
+			content: content,
+			mime:    "",
+			want:    fallback,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
Repository: getkin/kin-openapi
Pull request #99 (2019-06-02 18:49:04)

Fix bug in bearerFormat validation
The `bearerFormat` field in security schemas would only permit the values "JWT" and "", whereas the spec allows it to contain arbitrary strings. `bearerFormat` was also accepted for authentication types where it's
invalid, like "apiKey". Fixed the bug, modified one test and added another.

This fixes https://github.com/getkin/kin-openapi/issues/97.


Patch:
diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go
index e7a6cb6..fee586b 100644
--- a/openapi3/security_scheme.go
+++ b/openapi3/security_scheme.go
@@ -85,7 +85,6 @@ func (ss *SecurityScheme) Validate(c context.Context) error {
 	switch ss.Type {
 	case "apiKey":
 		hasIn = true
-		hasBearerFormat = true
 	case "http":
 		scheme := ss.Scheme
 		switch scheme {
@@ -120,14 +119,9 @@ func (ss *SecurityScheme) Validate(c context.Context) error {
 	}
 
 	// Validate "format"
-	if hasBearerFormat {
-		switch ss.BearerFormat {
-		case "", "JWT":
-		default:
-			return fmt.Errorf("Security scheme has unsupported 'bearerFormat' value '%s'", ss.BearerFormat)
-		}
-	} else if len(ss.BearerFormat) > 0 {
-		return errors.New("Security scheme of type 'apiKey' can't have 'bearerFormat'")
+	// "bearerFormat" is an arbitrary string so we only check if the scheme supports it
+	if !hasBearerFormat && len(ss.BearerFormat) > 0 {
+		return fmt.Errorf("Security scheme of type '%v' can't have 'bearerFormat'", ss.Type)
 	}
 
 	// Validate "flow"


Test patch:
diff --git a/openapi3/security_scheme_test.go b/openapi3/security_scheme_test.go
index c985532..43e0dc5 100644
--- a/openapi3/security_scheme_test.go
+++ b/openapi3/security_scheme_test.go
@@ -59,12 +59,24 @@ var securitySchemeExamples = []securitySchemeExample{
 		valid: true,
 	},
 	{
-		title: "JWT Bearer Sample",
+		title: "apiKey with bearerFormat",
+		raw: []byte(`
+{
+  "type": "apiKey",
+	"in": "header",
+	"name": "X-API-KEY",
+  "bearerFormat": "Arbitrary text"
+}
+`),
+		valid: false,
+	},
+	{
+		title: "Bearer Sample with arbitrary format",
 		raw: []byte(`
 {
   "type": "http",
   "scheme": "bearer",
-  "bearerFormat": "JWT"
+  "bearerFormat": "Arbitrary text"
 }
 `),
 		valid: true,
Repository: getkin/kin-openapi
Pull request #134 (2019-10-23 15:03:28)

Fixed validation of empty scopes
Fix for issue #133 


Patch:
diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go
index 6819d55..0e991fb 100644
--- a/openapi3/security_scheme.go
+++ b/openapi3/security_scheme.go
@@ -207,7 +207,7 @@ func (flow *OAuthFlow) Validate(c context.Context, typ oAuthFlowType) error {
 			return errors.New("An OAuth flow is missing 'tokenUrl in not implicit'")
 		}
 	}
-	if v := flow.Scopes; len(v) == 0 {
+	if v := flow.Scopes; v == nil {
 		return errors.New("An OAuth flow is missing 'scopes'")
 	}
 	return nil


Test patch:
diff --git a/openapi3/security_scheme_test.go b/openapi3/security_scheme_test.go
index 43e0dc5..7f013be 100644
--- a/openapi3/security_scheme_test.go
+++ b/openapi3/security_scheme_test.go
@@ -166,6 +166,36 @@ var securitySchemeExamples = []securitySchemeExample{
 	"in": "cookie",
 	"name": "somecookie"
 }
+`),
+		valid: true,
+	},
+
+	{
+		title: "OAuth Flow Object with no scopes",
+		raw: []byte(`
+{
+  "type": "oauth2",
+  "flows": {
+    "password": {
+      "tokenUrl": "https://example.com/api/oauth/token"
+    }
+  }
+}
+`),
+		valid: false,
+	},
+	{
+		title: "OAuth Flow Object with empty scopes",
+		raw: []byte(`
+{
+  "type": "oauth2",
+  "flows": {
+    "password": {
+			"tokenUrl": "https://example.com/api/oauth/token",
+			"scopes": {}
+    }
+  }
+}
 `),
 		valid: true,
 	},
Repository: getkin/kin-openapi
Pull request #139 (2019-11-01 23:42:23)

Use the full version specifier
The [OpenAPI spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md) requires that the full version identifier be used.

fenollp: How about setting `3.0.2`?
tschaub: Updated to use `3.0.2`.

Patch:
diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go
index 97a0e71..0ff1dc3 100644
--- a/openapi2conv/openapi2_conv.go
+++ b/openapi2conv/openapi2_conv.go
@@ -12,7 +12,7 @@ import (
 
 func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
 	result := &openapi3.Swagger{
-		OpenAPI:    "3.0",
+		OpenAPI:    "3.0.2",
 		Info:       &swagger.Info,
 		Components: openapi3.Components{},
 		Tags:       swagger.Tags,


Test patch:
diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go
index 84a053c..c712dd7 100644
--- a/openapi2conv/openapi2_conv_test.go
+++ b/openapi2conv/openapi2_conv_test.go
@@ -140,7 +140,7 @@ const exampleV2 = `
 
 const exampleV3 = `
 {
-  "openapi": "3.0",
+  "openapi": "3.0.2",
   "info": {"title":"MyAPI","version":"0.1"},
   "components": {},
   "tags": [
Repository: getkin/kin-openapi
Pull request #166 (2020-01-23 19:45:24)

Also resolve refs in additionalProperties


Patch:
diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go
index de69625..ef480d8 100644
--- a/openapi2conv/openapi2_conv.go
+++ b/openapi2conv/openapi2_conv.go
@@ -242,6 +242,9 @@ func ToV3SchemaRef(schema *openapi3.SchemaRef) *openapi3.SchemaRef {
 	for k, v := range schema.Value.Properties {
 		schema.Value.Properties[k] = ToV3SchemaRef(v)
 	}
+	if schema.Value.AdditionalProperties != nil {
+		schema.Value.AdditionalProperties = ToV3SchemaRef(schema.Value.AdditionalProperties)
+	}
 	return schema
 }
 
@@ -413,6 +416,9 @@ func FromV3SchemaRef(schema *openapi3.SchemaRef) *openapi3.SchemaRef {
 	for k, v := range schema.Value.Properties {
 		schema.Value.Properties[k] = FromV3SchemaRef(v)
 	}
+	if schema.Value.AdditionalProperties != nil {
+		schema.Value.AdditionalProperties = FromV3SchemaRef(schema.Value.AdditionalProperties)
+	}
 	return schema
 }
 


Test patch:
diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go
index 3f7cf5a..ff7522f 100644
--- a/openapi2conv/openapi2_conv_test.go
+++ b/openapi2conv/openapi2_conv_test.go
@@ -164,8 +164,14 @@ const exampleV2 = `
         "foo": {
           "type": "string"
         }
+      },
+	  "additionalProperties": {
+        "$ref": "#/definitions/ItemExtension"
       }
     },
+    "ItemExtension": {
+        "description": "It could be anything."
+    },
     "Error": {
       "description": "Error response.",
       "type": "object",
@@ -215,8 +221,14 @@ const exampleV3 = `
           "foo": {
             "type": "string"
           }
-        }
+        },
+	    "additionalProperties": {
+          "$ref": "#/components/schemas/ItemExtension"
+	    }
       },
+	  "ItemExtension": {
+		"description": "It could be anything."
+	  },
       "Error": {
         "description": "Error response.",
         "properties": {
Repository: getkin/kin-openapi
Pull request #169 (2020-01-29 18:26:20)

Treat nullable as a special case
Fixes https://github.com/getkin/kin-openapi/issues/168


Patch:
diff --git a/go.mod b/go.mod
index 5effe90..9f441f2 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/kr/pretty v0.1.0 // indirect
 	github.com/stretchr/testify v1.3.0
 	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
-	gopkg.in/yaml.v2 v2.2.7 // indirect
+	gopkg.in/yaml.v2 v2.2.8 // indirect
 )
 
 go 1.13
diff --git a/go.sum b/go.sum
index ee1f920..583c172 100644
--- a/go.sum
+++ b/go.sum
@@ -17,5 +17,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/openapi3/schema.go b/openapi3/schema.go
index 16c4655..1fec39e 100644
--- a/openapi3/schema.go
+++ b/openapi3/schema.go
@@ -595,6 +595,8 @@ func (schema *Schema) VisitJSON(value interface{}) error {
 
 func (schema *Schema) visitJSON(value interface{}, fast bool) (err error) {
 	switch value := value.(type) {
+	case nil:
+		return schema.visitJSONNull(fast)
 	case float64:
 		if math.IsNaN(value) {
 			return ErrSchemaInputNaN


Test patch:
diff --git a/openapi3/schema_test.go b/openapi3/schema_test.go
index 2bc9f0f..3c16101 100644
--- a/openapi3/schema_test.go
+++ b/openapi3/schema_test.go
@@ -134,6 +134,32 @@ var schemaExamples = []schemaExample{
 		},
 	},
 
+	{
+		Title: "NULLABLE ANYOF",
+		Schema: openapi3.NewAnyOfSchema(
+			openapi3.NewIntegerSchema(),
+			openapi3.NewFloat64Schema(),
+		).WithNullable(),
+		Serialization: map[string]interface{}{
+			"nullable": true,
+			"anyOf": []interface{}{
+				map[string]interface{}{"type": "integer"},
+				map[string]interface{}{"type": "number"},
+			},
+		},
+		AllValid: []interface{}{
+			nil,
+			42,
+			4.2,
+		},
+		AllInvalid: []interface{}{
+			true,
+			[]interface{}{42},
+			"bla",
+			map[string]interface{}{},
+		},
+	},
+
 	{
 		Title:  "BOOLEAN",
 		Schema: openapi3.NewBoolSchema(),
diff --git a/openapi3filter/router_test.go b/openapi3filter/router_test.go
index f78370c..ed7fe9e 100644
--- a/openapi3filter/router_test.go
+++ b/openapi3filter/router_test.go
@@ -12,8 +12,8 @@ import (
 
 func TestRouter(t *testing.T) {
 	var (
-		pathNotFound = "Path was not found"
-		methodNotAllowed = "Path doesn't support the HTTP method"
+		pathNotFound          = "Path was not found"
+		methodNotAllowed      = "Path doesn't support the HTTP method"
 		doesNotMatchAnyServer = "Does not match any server"
 	)
Repository: getkin/kin-openapi
Pull request #184 (2020-03-04 19:15:57)

Encode security requirements correctly

fenollp: Thanks for the catch! Could you add a simple test that can serve as a regressor?

Patch:
diff --git a/openapi3/security_requirements.go b/openapi3/security_requirements.go
index c2ea703..1d2c745 100644
--- a/openapi3/security_requirements.go
+++ b/openapi3/security_requirements.go
@@ -31,6 +31,9 @@ func NewSecurityRequirement() SecurityRequirement {
 }
 
 func (security SecurityRequirement) Authenticate(provider string, scopes ...string) SecurityRequirement {
+	if len(scopes) == 0 {
+		scopes = []string{} // Forces the variable to be encoded as an array instead of null
+	}
 	security[provider] = scopes
 	return security
 }


Test patch:
diff --git a/openapi3/security_requirements_test.go b/openapi3/security_requirements_test.go
new file mode 100644
index 0000000..d1103e5
--- /dev/null
+++ b/openapi3/security_requirements_test.go
@@ -0,0 +1,64 @@
+package openapi3
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestSecurityRequirementsEncoding(t *testing.T) {
+
+	tests := []struct {
+		requirements *SecurityRequirements
+		json         string
+	}{
+		{
+			requirements: NewSecurityRequirements(),
+			json:         `[]`,
+		},
+		{
+			requirements: NewSecurityRequirements().With(NewSecurityRequirement()),
+			json:         `[{}]`,
+		},
+	}
+
+	for _, test := range tests {
+
+		b, err := json.Marshal(test.requirements)
+		require.NoError(t, err)
+		require.Equal(t, test.json, string(b), "incorrect requirements encoding")
+	}
+}
+
+func TestSecurityRequirementEncoding(t *testing.T) {
+
+	tests := []struct {
+		requirement SecurityRequirement
+		json        string
+	}{
+		{
+			requirement: NewSecurityRequirement(),
+			json:        `{}`,
+		},
+		{
+			requirement: NewSecurityRequirement().Authenticate("provider"),
+			json:        `{"provider":[]}`,
+		},
+		{
+			requirement: NewSecurityRequirement().Authenticate("provider", "scope1"),
+			json:        `{"provider":["scope1"]}`,
+		},
+		{
+			requirement: NewSecurityRequirement().Authenticate("provider", "scope1", "scope2"),
+			json:        `{"provider":["scope1","scope2"]}`,
+		},
+	}
+
+	for _, test := range tests {
+
+		b, err := json.Marshal(test.requirement)
+		require.NoError(t, err)
+		require.Equal(t, test.json, string(b), "incorrect requirements encoding")
+	}
+}
Repository: getkin/kin-openapi
Pull request #656 (2022-11-07 03:12:47)

Add RegisterBodyEncoder
This is analogous to `RegisterBodyDecoder`


Patch:
diff --git a/openapi3filter/req_resp_encoder.go b/openapi3filter/req_resp_encoder.go
index dd410f5..36b7db6 100644
--- a/openapi3filter/req_resp_encoder.go
+++ b/openapi3filter/req_resp_encoder.go
@@ -16,8 +16,34 @@ func encodeBody(body interface{}, mediaType string) ([]byte, error) {
 	return encoder(body)
 }
 
-type bodyEncoder func(body interface{}) ([]byte, error)
+type BodyEncoder func(body interface{}) ([]byte, error)
 
-var bodyEncoders = map[string]bodyEncoder{
+var bodyEncoders = map[string]BodyEncoder{
 	"application/json": json.Marshal,
 }
+
+func RegisterBodyEncoder(contentType string, encoder BodyEncoder) {
+	if contentType == "" {
+		panic("contentType is empty")
+	}
+	if encoder == nil {
+		panic("encoder is not defined")
+	}
+	bodyEncoders[contentType] = encoder
+}
+
+// This call is not thread-safe: body encoders should not be created/destroyed by multiple goroutines.
+func UnregisterBodyEncoder(contentType string) {
+	if contentType == "" {
+		panic("contentType is empty")
+	}
+	delete(bodyEncoders, contentType)
+}
+
+// RegisteredBodyEncoder returns the registered body encoder for the given content type.
+//
+// If no encoder was registered for the given content type, nil is returned.
+// This call is not thread-safe: body encoders should not be created/destroyed by multiple goroutines.
+func RegisteredBodyEncoder(contentType string) BodyEncoder {
+	return bodyEncoders[contentType]
+}


Test patch:
diff --git a/openapi3filter/req_resp_encoder_test.go b/openapi3filter/req_resp_encoder_test.go
new file mode 100644
index 0000000..11fe2af
--- /dev/null
+++ b/openapi3filter/req_resp_encoder_test.go
@@ -0,0 +1,43 @@
+package openapi3filter
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestRegisterAndUnregisterBodyEncoder(t *testing.T) {
+	var encoder BodyEncoder
+	encoder = func(body interface{}) (data []byte, err error) {
+		return []byte(strings.Join(body.([]string), ",")), nil
+	}
+	contentType := "text/csv"
+	h := make(http.Header)
+	h.Set(headerCT, contentType)
+
+	originalEncoder := RegisteredBodyEncoder(contentType)
+	require.Nil(t, originalEncoder)
+
+	RegisterBodyEncoder(contentType, encoder)
+	require.Equal(t, fmt.Sprintf("%v", encoder), fmt.Sprintf("%v", RegisteredBodyEncoder(contentType)))
+
+	body := []string{"foo", "bar"}
+	got, err := encodeBody(body, contentType)
+
+	require.NoError(t, err)
+	require.Equal(t, []byte("foo,bar"), got)
+
+	UnregisterBodyEncoder(contentType)
+
+	originalEncoder = RegisteredBodyEncoder(contentType)
+	require.Nil(t, originalEncoder)
+
+	_, err = encodeBody(body, contentType)
+	require.Equal(t, &ParseError{
+		Kind:   KindUnsupportedFormat,
+		Reason: prefixUnsupportedCT + ` "text/csv"`,
+	}, err)
+}
Repository: getkin/kin-openapi
Pull request #670 (2022-11-17 17:06:36)

Support x-nullable
Adds support for the `x-nullable` convention for OpenAPI V2 conversion. Since nullable fields are not supported in the v2 spec a convention was been adopted of adding a `x-nullable: true` attribute to properties.

This PR adds support for setting the `nullable` attribute for V2 > V3 conversion which does support nullable fields and vice-versa.


Patch:
diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go
index 53b4b40..8c08205 100644
--- a/openapi2conv/openapi2_conv.go
+++ b/openapi2conv/openapi2_conv.go
@@ -485,6 +485,16 @@ func ToV3SchemaRef(schema *openapi3.SchemaRef) *openapi3.SchemaRef {
 	for i, v := range schema.Value.AllOf {
 		schema.Value.AllOf[i] = ToV3SchemaRef(v)
 	}
+	if val, ok := schema.Value.Extensions["x-nullable"]; ok {
+		var nullable bool
+
+		if err := json.Unmarshal(val.(json.RawMessage), &nullable); err == nil {
+			schema.Value.Nullable = nullable
+		}
+
+		delete(schema.Value.Extensions, "x-nullable")
+	}
+
 	return schema
 }
 
@@ -824,6 +834,11 @@ func FromV3SchemaRef(schema *openapi3.SchemaRef, components *openapi3.Components
 	for i, v := range schema.Value.AllOf {
 		schema.Value.AllOf[i], _ = FromV3SchemaRef(v, components)
 	}
+	if schema.Value.Nullable {
+		schema.Value.Nullable = false
+		schema.Value.Extensions["x-nullable"] = true
+	}
+
 	return schema, nil
 }
 


Test patch:
diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go
index 9edce54..3177721 100644
--- a/openapi2conv/openapi2_conv_test.go
+++ b/openapi2conv/openapi2_conv_test.go
@@ -89,7 +89,8 @@ const exampleV2 = `
 			"additionalProperties": true,
 			"properties": {
 				"foo": {
-					"type": "string"
+					"type": "string",
+					"x-nullable": true
 				},
 				"quux": {
 					"$ref": "#/definitions/ItemExtension"
@@ -463,7 +464,8 @@ const exampleV3 = `
 				"additionalProperties": true,
 				"properties": {
 					"foo": {
-						"type": "string"
+						"type": "string",
+						"nullable": true
 					},
 					"quux": {
 						"$ref": "#/components/schemas/ItemExtension"