Skip to content

Fix Response Schema Handling with Custom MIME Types #2019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion field_parser_v3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func TestDefaultFieldParserV3(t *testing.T) {
t.Parallel()

schema := spec.NewSchemaSpec()
schema.Spec.Type = []string{"string"}
schema.Spec.Type = &spec.SingleOrArray[string]{STRING}
parser := &Parser{}
fieldParser := newTagBaseFieldParserV3(
parser,
Expand Down
11 changes: 9 additions & 2 deletions operationv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,8 +956,15 @@ func (o *OperationV3) ParseResponseComment(commentLine string, astFile *ast.File
response := spec.NewResponseSpec()
response.Spec.Spec.Description = description

mimeType := "application/json" // TODO: set correct mimeType
setResponseSchema(response.Spec.Spec, mimeType, schema)
// Add the schema to all specified response MIME types
if len(o.responseMimeTypes) > 0 {
for _, mimeType := range o.responseMimeTypes {
setResponseSchema(response.Spec.Spec, mimeType, schema)
}
} else {
// Default to application/json if no MIME types were specified
setResponseSchema(response.Spec.Spec, "application/json", schema)
}

o.AddResponse(codeStr, response)
}
Expand Down
117 changes: 117 additions & 0 deletions operationv3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2082,3 +2082,120 @@ func TestParseServerCommentV3(t *testing.T) {
assert.Equal(t, "https://api.example.com/v2", operation.Servers[1].Spec.URL)
assert.Equal(t, "override path 2", operation.Servers[1].Spec.Description)
}

func TestResponseSchemaWithCustomMimeTypeV3(t *testing.T) {
t.Parallel()

t.Run("Schema ref is correctly associated with custom MIME type", func(t *testing.T) {
t.Parallel()

// Create operation with parser to handle the type reference
parser := New()
operation := NewOperationV3(parser)

// Create a mock type in the parser as a stand-in for model.OrderRow
parser.addTestType("model.OrderRow")

// First, set the response MIME type with @Produce
err := operation.ParseComment("/@Produce json-api", nil)
require.NoError(t, err)

// Then set the response with @Success
err = operation.ParseComment("/@Success 200 {object} model.OrderRow", nil)
require.NoError(t, err)

// Check that we have a response for status code 200
response, exists := operation.Responses.Spec.Response["200"]
require.True(t, exists, "Response for status code 200 should exist")

// Verify the correct MIME type (json-api -> application/vnd.api+json) has the schema reference
content := response.Spec.Spec.Content
require.NotNil(t, content, "Response content should not be nil")

// Check that application/vnd.api+json exists in the content map
apiJsonContent, exists := content["application/vnd.api+json"]
require.True(t, exists, "application/vnd.api+json content should exist")

// Verify the schema reference is correct
require.NotNil(t, apiJsonContent.Spec.Schema, "Schema should not be nil")
require.NotNil(t, apiJsonContent.Spec.Schema.Ref, "Schema ref should not be nil")
require.Equal(t, "#/components/schemas/model.OrderRow", apiJsonContent.Spec.Schema.Ref.Ref)

// Make sure the schema is NOT also defined under application/json
_, exists = content["application/json"]
require.False(t, exists, "application/json content should not exist when only json-api was specified")
})

t.Run("Default to application/json when no MIME type is specified", func(t *testing.T) {
t.Parallel()

// Create operation with parser to handle the type reference
parser := New()
operation := NewOperationV3(parser)

// Create a mock type in the parser
parser.addTestType("model.OrderRow")

// Only set the response with @Success, without any @Produce
err := operation.ParseComment("/@Success 200 {object} model.OrderRow", nil)
require.NoError(t, err)

// Check that we have a response for status code 200
response, exists := operation.Responses.Spec.Response["200"]
require.True(t, exists, "Response for status code 200 should exist")

// Verify application/json has the schema reference
content := response.Spec.Spec.Content
require.NotNil(t, content, "Response content should not be nil")

// Check that application/json exists in the content map
jsonContent, exists := content["application/json"]
require.True(t, exists, "application/json content should exist")

// Verify the schema reference is correct
require.NotNil(t, jsonContent.Spec.Schema, "Schema should not be nil")
require.NotNil(t, jsonContent.Spec.Schema.Ref, "Schema ref should not be nil")
require.Equal(t, "#/components/schemas/model.OrderRow", jsonContent.Spec.Schema.Ref.Ref)
})

t.Run("Multiple MIME types have the same schema reference", func(t *testing.T) {
t.Parallel()

// Create operation with parser to handle the type reference
parser := New()
operation := NewOperationV3(parser)

// Create a mock type in the parser
parser.addTestType("model.OrderRow")

// Set multiple MIME types
err := operation.ParseComment("/@Produce json,json-api", nil)
require.NoError(t, err)

// Set the response
err = operation.ParseComment("/@Success 200 {object} model.OrderRow", nil)
require.NoError(t, err)

// Check that we have a response for status code 200
response, exists := operation.Responses.Spec.Response["200"]
require.True(t, exists, "Response for status code 200 should exist")

// Verify both MIME types have the schema reference
content := response.Spec.Spec.Content
require.NotNil(t, content, "Response content should not be nil")

// Check application/json
jsonContent, exists := content["application/json"]
require.True(t, exists, "application/json content should exist")
require.NotNil(t, jsonContent.Spec.Schema, "Schema should not be nil")
require.NotNil(t, jsonContent.Spec.Schema.Ref, "Schema ref should not be nil")
require.Equal(t, "#/components/schemas/model.OrderRow", jsonContent.Spec.Schema.Ref.Ref)

// Check application/vnd.api+json
apiJsonContent, exists := content["application/vnd.api+json"]
require.True(t, exists, "application/vnd.api+json content should exist")
require.NotNil(t, apiJsonContent.Spec.Schema, "Schema should not be nil")
require.NotNil(t, apiJsonContent.Spec.Schema.Ref, "Schema ref should not be nil")
require.Equal(t, "#/components/schemas/model.OrderRow", apiJsonContent.Spec.Schema.Ref.Ref)
})
}