Skip to content

Commit 7286e9d

Browse files
authored
Merge pull request #4 from instacart/task/add-requests-examples-support
Add examples support to requests
2 parents e23bc8a + 1118b62 commit 7286e9d

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

rswag-specs/lib/rswag/specs/example_group_helpers.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ def parameter(attributes)
5151
end
5252
end
5353

54+
55+
def request_body_example(value:, summary: nil, name: nil)
56+
if metadata.key?(:operation)
57+
metadata[:operation][:request_examples] ||= []
58+
example = { value: value }
59+
example[:summary] = summary if summary
60+
# 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.
61+
example[:name] = name || metadata[:operation][:request_examples].length()
62+
metadata[:operation][:request_examples] << example
63+
end
64+
end
65+
5466
def response(code, description, metadata = {}, &block)
5567
metadata[:response] = { code: code, description: description }
5668
context(description, metadata, &block)

rswag-specs/lib/rswag/specs/swagger_formatter.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,18 @@ def stop(_notification = nil)
6060
if value && schema_param && mime_list
6161
value[:requestBody] = { content: {} } unless value.dig(:requestBody, :content)
6262
value[:requestBody][:required] = true if schema_param[:required]
63+
examples = value.dig(:request_examples)
6364
mime_list.each do |mime|
6465
value[:requestBody][:content][mime] = { schema: schema_param[:schema] }
66+
if examples
67+
value[:requestBody][:content][mime][:examples] ||= {}
68+
examples.map do |example|
69+
value[:requestBody][:content][mime][:examples][example[:name]] = {
70+
summary: example[:summary] || value[:summary],
71+
value: example[:value]
72+
}
73+
end
74+
end
6575
end
6676
end
6777

@@ -210,6 +220,7 @@ def remove_invalid_operation_keys!(value)
210220
is_hash = value.is_a?(Hash)
211221
value.delete(:consumes) if is_hash && value.dig(:consumes)
212222
value.delete(:produces) if is_hash && value.dig(:produces)
223+
value.delete(:request_examples) if is_hash && value.dig(:request_examples)
213224
end
214225
end
215226
end

rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,38 @@ module Specs
136136
end
137137
end
138138

139+
describe '#request_body_example(value:, summary: nil, name: nil)' do
140+
context "when adding one example" do
141+
before { subject.request_body_example(value: value)}
142+
let(:api_metadata) { { operation: {} } }
143+
let(:value) { { field: 'A', another_field: 'B' } }
144+
145+
it "assigns the example to the metadata" do
146+
expect(api_metadata[:operation][:request_examples].length()).to eq(1)
147+
expect(api_metadata[:operation][:request_examples][0]).to eq({ value: value, name: 0 })
148+
end
149+
end
150+
151+
context "when adding multiple examples with additional information" do
152+
before {
153+
subject.request_body_example(value: example_one)
154+
subject.request_body_example(value: example_two, name: example_two_name, summary: example_two_summary)
155+
}
156+
let(:api_metadata) { { operation: {} } }
157+
let(:example_one) { { field: 'A', another_field: 'B' } }
158+
let(:example_two) { { field: 'B', another_field: 'C' } }
159+
let(:example_two_name) { 'example_two' }
160+
let(:example_two_summary) { 'An example description' }
161+
162+
it "assigns all examples to the metadata" do
163+
expect(api_metadata[:operation][:request_examples].length()).to eq(2)
164+
expect(api_metadata[:operation][:request_examples][0]).to eq({ value: example_one, name: 0 })
165+
expect(api_metadata[:operation][:request_examples][1]).to eq({ value: example_two, name: example_two_name, summary: example_two_summary })
166+
end
167+
end
168+
end
169+
170+
139171
describe '#examples(example)' do
140172
let(:mime) { 'application/json' }
141173
let(:json_example) do

rswag-specs/spec/rswag/specs/swagger_formatter_spec.rb

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ module Specs
2323
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
2424
subject.example_group_finished(notification)
2525
end
26+
let(:request_examples) { nil }
2627
let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) }
2728
let(:api_metadata) do
29+
operation = { verb: :post, summary: 'Creates a blog', parameters: [{ type: :string }] }
30+
if request_examples
31+
operation[:request_examples] = request_examples
32+
end
2833
{
2934
path_item: { template: '/blogs', parameters: [{ type: :string }] },
30-
operation: { verb: :post, summary: 'Creates a blog', parameters: [{ type: :string }] },
35+
operation: operation,
3136
response: response_metadata,
3237
document: document
3338
}
@@ -494,6 +499,91 @@ module Specs
494499
after do
495500
FileUtils.rm_r(swagger_root) if File.exist?(swagger_root)
496501
end
502+
503+
504+
context 'with request examples' do
505+
let(:doc_2) do
506+
{
507+
paths: {
508+
'/path/' => {
509+
post: {
510+
summary: 'Retrieve Nested Paths',
511+
tags: ['nested Paths'],
512+
produces: ['application/json'],
513+
consumes: ['application/json'],
514+
parameters: [{
515+
in: :body,
516+
schema: {
517+
'$ref': '#/components/schemas/BlogPost'
518+
}
519+
},{
520+
in: :headers
521+
}],
522+
request_examples: [
523+
{
524+
name: 'basic',
525+
value: {
526+
some_field: 'Foo'
527+
},
528+
summary: 'An example'
529+
},
530+
{
531+
name: 'another_basic',
532+
value: {
533+
some_field: 'Bar'
534+
}
535+
}
536+
],
537+
}
538+
}
539+
},
540+
components: {
541+
schemas: {
542+
'BlogPost' => {
543+
type: 'object',
544+
properties: {
545+
some_field: {
546+
type: 'string',
547+
description: 'description'
548+
}
549+
}
550+
}
551+
}
552+
}
553+
}
554+
end
555+
556+
it 'removes remaining request_examples' do
557+
expect(doc_2[:paths]['/path/'][:post].keys).to eql([:summary, :tags, :parameters, :requestBody])
558+
end
559+
560+
it 'creates requestBody examples' do
561+
expect(doc_2[:paths]['/path/'][:post][:parameters]).to eql([{ in: :headers }])
562+
expect(doc_2[:paths]['/path/'][:post][:requestBody]).to eql(content: {
563+
'application/json' => {
564+
schema: { '$ref': '#/components/schemas/BlogPost' },
565+
examples: {
566+
'basic' => {
567+
value: {
568+
some_field: 'Foo'
569+
},
570+
summary: 'An example'
571+
},
572+
'another_basic' => {
573+
value: {
574+
some_field: 'Bar'
575+
},
576+
summary: 'Retrieve Nested Paths'
577+
}
578+
}
579+
}
580+
})
581+
end
582+
end
583+
584+
after do
585+
FileUtils.rm_r(swagger_root) if File.exist?(swagger_root)
586+
end
497587
end
498588
end
499589
end

0 commit comments

Comments
 (0)