diff --git a/rswag-specs/lib/rswag/specs/example_group_helpers.rb b/rswag-specs/lib/rswag/specs/example_group_helpers.rb index 2a2cdec29..be94f4c67 100644 --- a/rswag-specs/lib/rswag/specs/example_group_helpers.rb +++ b/rswag-specs/lib/rswag/specs/example_group_helpers.rb @@ -51,6 +51,18 @@ def parameter(attributes) end end + + def request_body_example(value:, summary: nil, name: nil) + if metadata.key?(:operation) + metadata[:operation][:request_examples] ||= [] + example = { value: value } + example[:summary] = summary if summary + # We need the examples to have a unique name for a set of examples, so just make the name the length if one isn't provided. + example[:name] = name || metadata[:operation][:request_examples].length() + metadata[:operation][:request_examples] << example + end + end + def response(code, description, metadata = {}, &block) metadata[:response] = { code: code, description: description } context(description, metadata, &block) diff --git a/rswag-specs/lib/rswag/specs/swagger_formatter.rb b/rswag-specs/lib/rswag/specs/swagger_formatter.rb index 56cac5b3a..ffc42bc4f 100644 --- a/rswag-specs/lib/rswag/specs/swagger_formatter.rb +++ b/rswag-specs/lib/rswag/specs/swagger_formatter.rb @@ -60,8 +60,18 @@ def stop(_notification = nil) if value && schema_param && mime_list value[:requestBody] = { content: {} } unless value.dig(:requestBody, :content) value[:requestBody][:required] = true if schema_param[:required] + examples = value.dig(:request_examples) mime_list.each do |mime| value[:requestBody][:content][mime] = { schema: schema_param[:schema] } + if examples + value[:requestBody][:content][mime][:examples] ||= {} + examples.map do |example| + value[:requestBody][:content][mime][:examples][example[:name]] = { + summary: example[:summary] || value[:summary], + value: example[:value] + } + end + end end end @@ -210,6 +220,7 @@ def remove_invalid_operation_keys!(value) is_hash = value.is_a?(Hash) value.delete(:consumes) if is_hash && value.dig(:consumes) value.delete(:produces) if is_hash && value.dig(:produces) + value.delete(:request_examples) if is_hash && value.dig(:request_examples) end end end diff --git a/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb b/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb index 40bca7bcf..e60a2ed3d 100644 --- a/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb +++ b/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb @@ -136,6 +136,38 @@ module Specs end end + describe '#request_body_example(value:, summary: nil, name: nil)' do + context "when adding one example" do + before { subject.request_body_example(value: value)} + let(:api_metadata) { { operation: {} } } + let(:value) { { field: 'A', another_field: 'B' } } + + it "assigns the example to the metadata" do + expect(api_metadata[:operation][:request_examples].length()).to eq(1) + expect(api_metadata[:operation][:request_examples][0]).to eq({ value: value, name: 0 }) + end + end + + context "when adding multiple examples with additional information" do + before { + subject.request_body_example(value: example_one) + subject.request_body_example(value: example_two, name: example_two_name, summary: example_two_summary) + } + let(:api_metadata) { { operation: {} } } + let(:example_one) { { field: 'A', another_field: 'B' } } + let(:example_two) { { field: 'B', another_field: 'C' } } + let(:example_two_name) { 'example_two' } + let(:example_two_summary) { 'An example description' } + + it "assigns all examples to the metadata" do + expect(api_metadata[:operation][:request_examples].length()).to eq(2) + expect(api_metadata[:operation][:request_examples][0]).to eq({ value: example_one, name: 0 }) + expect(api_metadata[:operation][:request_examples][1]).to eq({ value: example_two, name: example_two_name, summary: example_two_summary }) + end + end + end + + describe '#examples(example)' do let(:mime) { 'application/json' } let(:json_example) do diff --git a/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb b/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb index 118f064bb..0af302bdf 100644 --- a/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb +++ b/rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb @@ -23,11 +23,16 @@ module Specs allow(config).to receive(:get_swagger_doc).and_return(swagger_doc) subject.example_group_finished(notification) end + let(:request_examples) { nil } let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) } let(:api_metadata) do + operation = { verb: :post, summary: 'Creates a blog', parameters: [{ type: :string }] } + if request_examples + operation[:request_examples] = request_examples + end { path_item: { template: '/blogs', parameters: [{ type: :string }] }, - operation: { verb: :post, summary: 'Creates a blog', parameters: [{ type: :string }] }, + operation: operation, response: response_metadata, document: document } @@ -494,6 +499,91 @@ module Specs after do FileUtils.rm_r(swagger_root) if File.exist?(swagger_root) end + + + context 'with request examples' do + let(:doc_2) do + { + paths: { + '/path/' => { + post: { + summary: 'Retrieve Nested Paths', + tags: ['nested Paths'], + produces: ['application/json'], + consumes: ['application/json'], + parameters: [{ + in: :body, + schema: { + '$ref': '#/components/schemas/BlogPost' + } + },{ + in: :headers + }], + request_examples: [ + { + name: 'basic', + value: { + some_field: 'Foo' + }, + summary: 'An example' + }, + { + name: 'another_basic', + value: { + some_field: 'Bar' + } + } + ], + } + } + }, + components: { + schemas: { + 'BlogPost' => { + type: 'object', + properties: { + some_field: { + type: 'string', + description: 'description' + } + } + } + } + } + } + end + + it 'removes remaining request_examples' do + expect(doc_2[:paths]['/path/'][:post].keys).to eql([:summary, :tags, :parameters, :requestBody]) + end + + it 'creates requestBody examples' do + expect(doc_2[:paths]['/path/'][:post][:parameters]).to eql([{ in: :headers }]) + expect(doc_2[:paths]['/path/'][:post][:requestBody]).to eql(content: { + 'application/json' => { + schema: { '$ref': '#/components/schemas/BlogPost' }, + examples: { + 'basic' => { + value: { + some_field: 'Foo' + }, + summary: 'An example' + }, + 'another_basic' => { + value: { + some_field: 'Bar' + }, + summary: 'Retrieve Nested Paths' + } + } + } + }) + end + end + + after do + FileUtils.rm_r(swagger_root) if File.exist?(swagger_root) + end end end end