Repository: getkin/kin-openapi
Pull request #340 (2021-04-12 13:17:21)

introduce openapi3filter.RegisteredBodyDecoder
Fixes https://github.com/getkin/kin-openapi/issues/339


Patch:
diff --git a/openapi3filter/req_resp_decoder.go b/openapi3filter/req_resp_decoder.go
index d192664..b9b0cd8 100644
--- a/openapi3filter/req_resp_decoder.go
+++ b/openapi3filter/req_resp_decoder.go
@@ -767,10 +767,19 @@ type BodyDecoder func(io.Reader, http.Header, *openapi3.SchemaRef, EncodingFn) (
 // By default, there is content type "application/json" is supported only.
 var bodyDecoders = make(map[string]BodyDecoder)
 
+// RegisteredBodyDecoder returns the registered body decoder for the given content type.
+//
+// If no decoder was registered for the given content type, nil is returned.
+// This call is not thread-safe: body decoders should not be created/destroyed by multiple goroutines.
+func RegisteredBodyDecoder(contentType string) BodyDecoder {
+	return bodyDecoders[contentType]
+}
+
 // RegisterBodyDecoder registers a request body's decoder for a content type.
 //
 // If a decoder for the specified content type already exists, the function replaces
 // it with the specified decoder.
+// This call is not thread-safe: body decoders should not be created/destroyed by multiple goroutines.
 func RegisterBodyDecoder(contentType string, decoder BodyDecoder) {
 	if contentType == "" {
 		panic("contentType is empty")
@@ -784,6 +793,7 @@ func RegisterBodyDecoder(contentType string, decoder BodyDecoder) {
 // UnregisterBodyDecoder dissociates a body decoder from a content type.
 //
 // Decoding this content type will result in an error.
+// This call is not thread-safe: body decoders should not be created/destroyed by multiple goroutines.
 func UnregisterBodyDecoder(contentType string) {
 	if contentType == "" {
 		panic("contentType is empty")


Test patch:
diff --git a/openapi3filter/req_resp_decoder_test.go b/openapi3filter/req_resp_decoder_test.go
index b6d603e..c461da9 100644
--- a/openapi3filter/req_resp_decoder_test.go
+++ b/openapi3filter/req_resp_decoder_test.go
@@ -1187,39 +1187,42 @@ func newTestMultipartForm(parts []*testFormPart) (io.Reader, string, error) {
 }
 
 func TestRegisterAndUnregisterBodyDecoder(t *testing.T) {
-	var (
-		contentType = "text/csv"
-		decoder     = func(body io.Reader, h http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (interface{}, error) {
-			data, err := ioutil.ReadAll(body)
-			if err != nil {
-				return nil, err
-			}
-			var vv []interface{}
-			for _, v := range strings.Split(string(data), ",") {
-				vv = append(vv, v)
-			}
-			return vv, nil
+	var decoder BodyDecoder
+	decoder = func(body io.Reader, h http.Header, schema *openapi3.SchemaRef, encFn EncodingFn) (decoded interface{}, err error) {
+		var data []byte
+		if data, err = ioutil.ReadAll(body); err != nil {
+			return
 		}
-		schema  = openapi3.NewArraySchema().WithItems(openapi3.NewStringSchema()).NewRef()
-		encFn   = func(string) *openapi3.Encoding { return nil }
-		body    = strings.NewReader("foo,bar")
-		want    = []interface{}{"foo", "bar"}
-		wantErr = &ParseError{Kind: KindUnsupportedFormat}
-	)
+		return strings.Split(string(data), ","), nil
+	}
+	contentType := "text/csv"
 	h := make(http.Header)
 	h.Set(headerCT, contentType)
 
+	originalDecoder := RegisteredBodyDecoder(contentType)
+	require.Nil(t, originalDecoder)
+
 	RegisterBodyDecoder(contentType, decoder)
+	require.Equal(t, fmt.Sprintf("%v", decoder), fmt.Sprintf("%v", RegisteredBodyDecoder(contentType)))
+
+	body := strings.NewReader("foo,bar")
+	schema := openapi3.NewArraySchema().WithItems(openapi3.NewStringSchema()).NewRef()
+	encFn := func(string) *openapi3.Encoding { return nil }
 	got, err := decodeBody(body, h, schema, encFn)
 
 	require.NoError(t, err)
-	require.Truef(t, reflect.DeepEqual(got, want), "got %v, want %v", got, want)
+	require.Equal(t, []string{"foo", "bar"}, got)
 
 	UnregisterBodyDecoder(contentType)
-	_, err = decodeBody(body, h, schema, encFn)
 
-	require.Error(t, err)
-	require.Truef(t, matchParseError(err, wantErr), "got error:\n%v\nwant error:\n%v", err, wantErr)
+	originalDecoder = RegisteredBodyDecoder(contentType)
+	require.Nil(t, originalDecoder)
+
+	_, err = decodeBody(body, h, schema, encFn)
+	require.Equal(t, &ParseError{
+		Kind:   KindUnsupportedFormat,
+		Reason: prefixUnsupportedCT + ` "text/csv"`,
+	}, err)
 }
 
 func matchParseError(got, want error) bool {