From ff01e36780ab2e4bdf5b2dc4e9ff5b4d432cb138 Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Tue, 25 Jun 2024 10:46:48 +0200 Subject: [PATCH] Preserve existing media type value during response parsing (#118) --- openapi3/reflect.go | 11 ++--- openapi3/reflect_test.go | 89 +++++++++++++++++++++++++++++++++++++++ openapi31/reflect.go | 11 ++--- openapi31/reflect_test.go | 89 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 14 deletions(-) diff --git a/openapi3/reflect.go b/openapi3/reflect.go index afae59e..faf6742 100644 --- a/openapi3/reflect.go +++ b/openapi3/reflect.go @@ -717,13 +717,10 @@ func (r *Reflector) parseJSONResponse(resp *Response, oc openapi.OperationContex contentType = mimeJSON } - resp.Content[contentType] = MediaType{ - Schema: &oaiSchema, - Example: nil, - Examples: nil, - Encoding: nil, - MapOfAnything: nil, - } + mt := resp.Content[contentType] + mt.Schema = &oaiSchema + + resp.Content[contentType] = mt if sch.Description != nil && resp.Description == "" { resp.Description = *sch.Description diff --git a/openapi3/reflect_test.go b/openapi3/reflect_test.go index 6b30525..dd2db25 100644 --- a/openapi3/reflect_test.go +++ b/openapi3/reflect_test.go @@ -1209,3 +1209,92 @@ func TestReflector_AddOperation_jsonschemaStruct(t *testing.T) { } }`, r.SpecSchema()) } + +func TestNewReflector_examples(t *testing.T) { + r := openapi3.NewReflector() + + op, err := r.NewOperationContext(http.MethodGet, "/") + require.NoError(t, err) + + type O1 struct { + F1 int `json:"f1,omitempty"` + Code string `json:"code"` + } + + type O2 struct { + F2 int `json:"f2,omitempty"` + Code string `json:"code"` + } + + st := http.StatusCreated + + op.AddRespStructure(jsonschema.OneOf(O1{}, O2{}), func(cu *openapi.ContentUnit) { + cu.HTTPStatus = st + }) + + if o3, ok := op.(openapi3.OperationExposer); ok { + c := openapi3.MediaType{} + c.Examples = map[string]openapi3.ExampleOrRef{ + "responseOne": { + Example: (&openapi3.Example{}).WithSummary("First possible answer").WithValue(O1{Code: "1234567890123456789012"}), + }, + "responseTwo": { + Example: (&openapi3.Example{}).WithSummary("Other possible answer").WithValue(O2{Code: "0000000000000000000000"}), + }, + } + resp := openapi3.Response{} + resp.WithContentItem("application/json", c) + + o3.Operation().Responses.WithMapOfResponseOrRefValuesItem(strconv.Itoa(st), openapi3.ResponseOrRef{ + Response: &resp, + }) + } + + require.NoError(t, r.AddOperation(op)) + assertjson.EqMarshal(t, `{ + "openapi":"3.0.3","info":{"title":"","version":""}, + "paths":{ + "/":{ + "get":{ + "responses":{ + "201":{ + "description":"Created", + "content":{ + "application/json":{ + "schema":{ + "oneOf":[ + {"$ref":"#/components/schemas/Openapi3TestO1"}, + {"$ref":"#/components/schemas/Openapi3TestO2"} + ] + }, + "examples":{ + "responseOne":{ + "summary":"First possible answer", + "value":{"code":"1234567890123456789012"} + }, + "responseTwo":{ + "summary":"Other possible answer", + "value":{"code":"0000000000000000000000"} + } + } + } + } + } + } + } + } + }, + "components":{ + "schemas":{ + "Openapi3TestO1":{ + "type":"object", + "properties":{"code":{"type":"string"},"f1":{"type":"integer"}} + }, + "Openapi3TestO2":{ + "type":"object", + "properties":{"code":{"type":"string"},"f2":{"type":"integer"}} + } + } + } + }`, r.SpecSchema()) +} diff --git a/openapi31/reflect.go b/openapi31/reflect.go index be9ac64..fc125b0 100644 --- a/openapi31/reflect.go +++ b/openapi31/reflect.go @@ -666,13 +666,10 @@ func (r *Reflector) parseJSONResponse(resp *Response, oc openapi.OperationContex contentType = mimeJSON } - resp.Content[contentType] = MediaType{ - Schema: sm, - Example: nil, - Examples: nil, - Encoding: nil, - MapOfAnything: nil, - } + mt := resp.Content[contentType] + mt.Schema = sm + + resp.Content[contentType] = mt if sch.Description != nil && resp.Description == "" { resp.Description = *sch.Description diff --git a/openapi31/reflect_test.go b/openapi31/reflect_test.go index 524e4df..be0b9e8 100644 --- a/openapi31/reflect_test.go +++ b/openapi31/reflect_test.go @@ -1337,3 +1337,92 @@ func TestReflector_AddOperation_jsonschemaStruct(t *testing.T) { } }`, r.SpecSchema()) } + +func TestNewReflector_examples(t *testing.T) { + r := openapi31.NewReflector() + + op, err := r.NewOperationContext(http.MethodGet, "/") + require.NoError(t, err) + + type O1 struct { + F1 int `json:"f1,omitempty"` + Code string `json:"code"` + } + + type O2 struct { + F2 int `json:"f2,omitempty"` + Code string `json:"code"` + } + + st := http.StatusCreated + + op.AddRespStructure(jsonschema.OneOf(O1{}, O2{}), func(cu *openapi.ContentUnit) { + cu.HTTPStatus = st + }) + + if o3, ok := op.(openapi31.OperationExposer); ok { + c := openapi31.MediaType{} + c.Examples = map[string]openapi31.ExampleOrReference{ + "responseOne": { + Example: (&openapi31.Example{}).WithSummary("First possible answer").WithValue(O1{Code: "1234567890123456789012"}), + }, + "responseTwo": { + Example: (&openapi31.Example{}).WithSummary("Other possible answer").WithValue(O2{Code: "0000000000000000000000"}), + }, + } + resp := openapi31.Response{} + resp.WithContentItem("application/json", c) + + o3.Operation().ResponsesEns().WithMapOfResponseOrReferenceValuesItem(strconv.Itoa(st), openapi31.ResponseOrReference{ + Response: &resp, + }) + } + + require.NoError(t, r.AddOperation(op)) + assertjson.EqMarshal(t, `{ + "openapi":"3.1.0","info":{"title":"","version":""}, + "paths":{ + "/":{ + "get":{ + "responses":{ + "201":{ + "description":"Created", + "content":{ + "application/json":{ + "schema":{ + "oneOf":[ + {"$ref":"#/components/schemas/Openapi31TestO1"}, + {"$ref":"#/components/schemas/Openapi31TestO2"} + ] + }, + "examples":{ + "responseOne":{ + "summary":"First possible answer", + "value":{"code":"1234567890123456789012"} + }, + "responseTwo":{ + "summary":"Other possible answer", + "value":{"code":"0000000000000000000000"} + } + } + } + } + } + } + } + } + }, + "components":{ + "schemas":{ + "Openapi31TestO1":{ + "properties":{"code":{"type":"string"},"f1":{"type":"integer"}}, + "type":"object" + }, + "Openapi31TestO2":{ + "properties":{"code":{"type":"string"},"f2":{"type":"integer"}}, + "type":"object" + } + } + } + }`, r.SpecSchema()) +}