diff --git a/rswag-specs/lib/rswag/specs/example_group_helpers.rb b/rswag-specs/lib/rswag/specs/example_group_helpers.rb index 0cf89d9..591a7e9 100644 --- a/rswag-specs/lib/rswag/specs/example_group_helpers.rb +++ b/rswag-specs/lib/rswag/specs/example_group_helpers.rb @@ -75,46 +75,6 @@ module Rswag metadata[:response][:examples] = example end - ## OA3 - # # checks the examples in the parameters should be able to add $ref and externalValue examples. - # # This syntax would look something like this in the integration _spec.rb file - # # - # # request_body_json schema: { '$ref' => '#/components/schemas/blog' }, - # # examples: [:blog, {name: :external_blog, - # # externalValue: 'http://api.sample.org/myjson_example'}, - # # {name: :another_example, - # # '$ref' => '#/components/examples/flexible_blog_example'}] - # # The first value :blog, points to a let param of the same name, and is used to make the request in the - # # integration test (it is used to build the request payload) - # # - # # The second item in the array shows how to add an externalValue for the examples in the requestBody section - # # The third item shows how to add a $ref item that points to the components/examples section of the swagger spec. - # # - # # NOTE: that the externalValue will produce valid example syntax in the swagger output, but swagger-ui - # # will not show it yet - # def merge_other_examples!(example_metadata) - # # example.metadata[:operation][:requestBody][:content]['application/json'][:examples] - # content_node = example_metadata[:operation][:requestBody][:content]['application/json'] - # return unless content_node - - # external_example = example_metadata[:operation]&.dig(:parameters)&.detect { |p| p[:in] == :body && p[:name].is_a?(Hash) && p[:name][:externalValue] } || {} - # ref_example = example_metadata[:operation]&.dig(:parameters)&.detect { |p| p[:in] == :body && p[:name].is_a?(Hash) && p[:name]['$ref'] } || {} - # examples_node = content_node[:examples] ||= {} - - # nodes_to_add = [] - # nodes_to_add << external_example unless external_example.empty? - # nodes_to_add << ref_example unless ref_example.empty? - - # nodes_to_add.each do |node| - # json_request_examples = examples_node ||= {} - # other_name = node[:name][:name] - # other_key = node[:name][:externalValue] ? :externalValue : '$ref' - # if other_name - # json_request_examples.merge!(other_name => {other_key => node[:param_value]}) - # end - # end - # end - def run_test!(&block) # NOTE: rspec 2.x support if RSPEC_VERSION < 3 @@ -135,30 +95,6 @@ module Rswag assert_response_matches_metadata(example.metadata, &block) example.instance_exec(response, &block) if block_given? end - - ## OA3 - # after do |example| - # body_parameter = example.metadata[:operation]&.dig(:parameters)&.detect { |p| p[:in] == :body && p[:required] } - - # if body_parameter && respond_to?(body_parameter[:name]) && example.metadata[:operation][:requestBody][:content]['application/json'] - # # save response examples by default - # if example.metadata[:response][:examples].nil? || example.metadata[:response][:examples].empty? - # example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) } unless response.body.to_s.empty? - # end - - # # save request examples using the let(:param_name) { REQUEST_BODY_HASH } syntax in the test - # if response.code.to_s =~ /^2\d{2}$/ - # example.metadata[:operation][:requestBody][:content]['application/json'] = { examples: {} } unless example.metadata[:operation][:requestBody][:content]['application/json'][:examples] - # json_request_examples = example.metadata[:operation][:requestBody][:content]['application/json'][:examples] - # json_request_examples[body_parameter[:name]] = { value: send(body_parameter[:name]) } - - # example.metadata[:operation][:requestBody][:content]['application/json'][:examples] = json_request_examples - # end - # end - - # self.class.merge_other_examples!(example.metadata) if example.metadata[:operation][:requestBody] - - # end end end end diff --git a/rswag-specs/lib/rswag/specs/extended_schema.rb b/rswag-specs/lib/rswag/specs/extended_schema.rb index 9923bda..3af8efc 100644 --- a/rswag-specs/lib/rswag/specs/extended_schema.rb +++ b/rswag-specs/lib/rswag/specs/extended_schema.rb @@ -15,9 +15,7 @@ module Rswag class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) - ## OA3 - # return if data.nil? && (current_schema.schema['nullable'] == true || current_schema.schema['x-nullable'] == true) - return if data.nil? && current_schema.schema['x-nullable'] == true + return if data.nil? && (current_schema.schema['nullable'] == true || current_schema.schema['x-nullable'] == true) super end diff --git a/rswag-specs/lib/rswag/specs/request_factory.rb b/rswag-specs/lib/rswag/specs/request_factory.rb index 5af3649..e5dff39 100644 --- a/rswag-specs/lib/rswag/specs/request_factory.rb +++ b/rswag-specs/lib/rswag/specs/request_factory.rb @@ -196,15 +196,6 @@ module Rswag body_param = parameters.select { |p| p[:in] == :body }.first body_param ? example.send(body_param[:name]).to_json : nil end - ## OA3 - # def build_json_payload(parameters, example) - # body_param = parameters.select { |p| p[:in] == :body && p[:name].is_a?(Symbol) }.first - # return nil unless body_param - - # source_body_param = example.send(body_param[:name]) if body_param[:name] && example.respond_to?(body_param[:name]) - # source_body_param ||= body_param[:param_value] - # source_body_param ? source_body_param.to_json : nil - # end def doc_version(doc) doc[:openapi] || doc[:swagger] || '3' diff --git a/rswag-specs/lib/rswag/specs/swagger_formatter.rb b/rswag-specs/lib/rswag/specs/swagger_formatter.rb index 7cda583..0b15f12 100644 --- a/rswag-specs/lib/rswag/specs/swagger_formatter.rb +++ b/rswag-specs/lib/rswag/specs/swagger_formatter.rb @@ -102,17 +102,6 @@ module Rswag def metadata_to_swagger(metadata) response_code = metadata[:response][:code] response = metadata[:response].reject { |k, _v| k == :code } - ## OA3 - # content_type = metadata[:response][:content].present? ? metadata[:response][:content].keys.first : 'application/json' - # # need to merge in to response - # if response[:examples]&.dig(content_type) - # example = response[:examples].dig(content_type).dup - # schema = response.dig(:content, content_type, :schema) - # new_hash = {example: example} - # new_hash[:schema] = schema if schema - # response.merge!(content: { content_type => new_hash }) - # response.delete(:examples) - # end verb = metadata[:operation][:verb] operation = metadata[:operation] 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 b3d6d33..2922523 100644 --- a/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb +++ b/rswag-specs/spec/rswag/specs/example_group_helpers_spec.rb @@ -62,40 +62,6 @@ module Rswag end end - ## OA3 - # describe '#request_body_json(schema)' do - # let(:api_metadata) { { path_item: {}, operation: {} } } # i.e. operation defined - # context 'when required is not supplied' do - # before { subject.request_body_json(schema: { type: 'object' }) } - - # it 'adds required true by default' do - # expect(api_metadata[:operation][:requestBody]).to match( - # required: true, content: { 'application/json' => { schema: { type: 'object' } } } - # ) - # end - # end - - # context 'when required is supplied' do - # before { subject.request_body_json(schema: { type: 'object' }, required: false) } - - # it 'adds required false' do - # expect(api_metadata[:operation][:requestBody]).to match( - # required: false, content: { 'application/json' => { schema: { type: 'object' } } } - # ) - # end - # end - - # context 'when required is supplied' do - # before { subject.request_body_json(schema: { type: 'object' }, description: 'my description') } - - # it 'adds description' do - # expect(api_metadata[:operation][:requestBody]).to match( - # description: 'my description', required: true, content: { 'application/json' => { schema: { type: 'object' } } } - # ) - # end - # end - # end - describe '#parameter(attributes)' do context "when called at the 'path' level" do before { subject.parameter(name: :blog, in: :body, schema: { type: 'object' }) } diff --git a/rswag-specs/spec/rswag/specs/example_helpers_spec.rb b/rswag-specs/spec/rswag/specs/example_helpers_spec.rb index 52394b4..0f3e1ba 100644 --- a/rswag-specs/spec/rswag/specs/example_helpers_spec.rb +++ b/rswag-specs/spec/rswag/specs/example_helpers_spec.rb @@ -63,8 +63,6 @@ module Rswag '/blogs/1/comments/2?q1=foo&api_key=fookey', '{"text":"Some comment"}', { 'CONTENT_TYPE' => 'application/json' } - ## OA3 - # 'CONTENT_TYPE' => 'application/json' ) end end diff --git a/rswag-specs/spec/rswag/specs/request_factory_spec.rb b/rswag-specs/spec/rswag/specs/request_factory_spec.rb index 2f2e5ff..aff5fb4 100644 --- a/rswag-specs/spec/rswag/specs/request_factory_spec.rb +++ b/rswag-specs/spec/rswag/specs/request_factory_spec.rb @@ -249,10 +249,6 @@ module Rswag context 'apiKey' do before do swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: key_location } } - ## OA3 - # swagger_doc[:components] = { securitySchemes: { - # apiKey: { type: :apiKey, name: 'api_key', in: key_location } - # } } metadata[:operation][:security] = [apiKey: []] allow(example).to receive(:api_key).and_return('foobar') end @@ -294,10 +290,6 @@ module Rswag context 'oauth2' do before do swagger_doc[:securityDefinitions] = { oauth2: { type: :oauth2, scopes: ['read:blogs'] } } - ## OA3 - # swagger_doc[:components] = { securitySchemes: { - # oauth2: { type: :oauth2, scopes: ['read:blogs'] } - # } } metadata[:operation][:security] = [oauth2: ['read:blogs']] allow(example).to receive(:Authorization).and_return('Bearer foobar') end @@ -313,11 +305,6 @@ module Rswag basic: { type: :basic }, api_key: { type: :apiKey, name: 'api_key', in: :query } } - ## OA3 - # swagger_doc[:components] = { securitySchemes: { - # basic: { type: :basic }, - # api_key: { type: :apiKey, name: 'api_key', in: :query } - # } } metadata[:operation][:security] = [{ basic: [], api_key: [] }] allow(example).to receive(:Authorization).and_return('Basic foobar') allow(example).to receive(:api_key).and_return('foobar') @@ -406,8 +393,6 @@ module Rswag context 'global security requirements' do before do swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: :query } } - ## OA3 - # swagger_doc[:components] = { securitySchemes: { apiKey: { type: :apiKey, name: 'api_key', in: :query } } } swagger_doc[:security] = [apiKey: []] allow(example).to receive(:api_key).and_return('foobar') end diff --git a/rswag-specs/spec/rswag/specs/response_validator_spec.rb b/rswag-specs/spec/rswag/specs/response_validator_spec.rb index a4c2bc6..e4c8e9c 100644 --- a/rswag-specs/spec/rswag/specs/response_validator_spec.rb +++ b/rswag-specs/spec/rswag/specs/response_validator_spec.rb @@ -24,16 +24,6 @@ module Rswag properties: { text: { type: :string } }, required: ['text'] } - ## OA3 - # content: { - # 'application/json' => { - # schema: { - # type: :object, - # properties: { text: { type: :string } }, - # required: ['text'] - # } - # } - # } } } end diff --git a/test-app/db/schema.rb b/test-app/db/schema.rb index e01f8f3..440d919 100644 --- a/test-app/db/schema.rb +++ b/test-app/db/schema.rb @@ -2,11 +2,11 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# This file is the source Rails uses to define your schema when running `rails -# db:schema:load`. When creating a new database, `rails db:schema:load` tends to -# be faster and is potentially less error prone than running all of your -# migrations from scratch. Old migrations may fail to apply correctly if those -# migrations use external dependencies or application code. +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended that you check this file into your version control system. diff --git a/test-app/spec/integration/new_blogs_spec.rb b/test-app/spec/integration/new_blogs_spec.rb deleted file mode 100644 index 9706648..0000000 --- a/test-app/spec/integration/new_blogs_spec.rb +++ /dev/null @@ -1,170 +0,0 @@ -# # frozen_string_literal: true - -# require 'swagger_helper' - -# RSpec.describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do -# let(:api_key) { 'fake_key' } - -# path '/blogs' do -# post 'Creates a blog' do -# tags 'Blogs' -# description 'Creates a new blog from provided data' -# operationId 'createBlog' -# consumes 'application/json' -# produces 'application/json' - -# request_body_json schema: { '$ref' => '#/components/schemas/blog' }, -# examples: :blog - -# request_body_text_plain -# request_body_xml schema: { '$ref' => '#/components/schemas/blog' } - -# let(:blog) { { blog: { title: 'foo', content: 'bar' } } } - -# response '201', 'blog created' do -# schema '$ref' => '#/components/schemas/blog' -# run_test! -# end - -# response '422', 'invalid request' do -# schema '$ref' => '#/components/schemas/errors_object' -# let(:blog) { { blog: { title: 'foo' } } } - -# run_test! do |response| -# expect(response.body).to include("can't be blank") -# end -# end -# end - -# get 'Searches blogs' do -# tags 'Blogs' -# description 'Searches blogs by keywords' -# operationId 'searchBlogs' -# produces 'application/json' -# parameter name: :keywords, in: :query, type: 'string' - -# let(:keywords) { 'foo bar' } - -# response '200', 'success' do -# schema type: 'array', items: { '$ref' => '#/components/schemas/blog' } -# run_test! -# end - -# response '406', 'unsupported accept header' do -# let(:Accept) { 'application/foo' } -# run_test! -# end -# end -# end - -# path '/blogs/flexible' do -# post 'Creates a blog flexible body' do -# tags 'Blogs' -# description 'Creates a flexible blog from provided data' -# operationId 'createFlexibleBlog' -# consumes 'application/json' -# produces 'application/json' - -# request_body_json schema: { -# :oneOf => [{'$ref' => '#/components/schemas/blog'}, -# {'$ref' => '#/components/schemas/flexible_blog'}] -# }, -# examples: :flexible_blog - -# let(:flexible_blog) { { blog: { headline: 'my headline', text: 'my text' } } } - -# response '201', 'flexible blog created' do -# schema :oneOf => [{'$ref' => '#/components/schemas/blog'},{'$ref' => '#/components/schemas/flexible_blog'}] -# run_test! -# end -# end -# end - -# path '/blogs/alternate' do -# post 'Creates a blog - different :examples in requestBody' do -# tags 'Blogs' -# description 'Creates a new blog from provided data' -# operationId 'createAlternateBlog' -# consumes 'application/json' -# produces 'application/json' - -# # NOTE: the externalValue: http://... is valid 3.0 spec, but swagger-UI does NOT support it yet -# # https://github.com/swagger-api/swagger-ui/issues/5433 -# request_body_json schema: { '$ref' => '#/components/schemas/blog' }, -# examples: [:blog, {name: :external_blog, -# externalValue: 'http://api.sample.org/myjson_example'}, -# {name: :another_example, -# '$ref' => '#/components/examples/flexible_blog_example'}] - -# let(:blog) { { blog: { title: 'alt title', content: 'alt bar' } } } - -# response '201', 'blog created' do -# schema '$ref' => '#/components/schemas/blog' -# run_test! -# end -# end -# end - - - -# path '/blogs/{id}' do - - -# let(:id) { blog.id } -# let(:blog) { Blog.create(title: 'foo', content: 'bar', thumbnail: 'thumbnail.png') } - -# get 'Retrieves a blog' do -# tags 'Blogs' -# description 'Retrieves a specific blog by id' -# operationId 'getBlog' -# produces 'application/json' - -# parameter name: :id, in: :path, type: :string - -# response '200', 'blog found' do -# header 'ETag', type: :string -# header 'Last-Modified', type: :string -# header 'Cache-Control', type: :string - -# schema '$ref' => '#/components/schemas/blog' - -# examples 'application/json' => { -# id: 1, -# title: 'Hello world!', -# content: 'Hello world and hello universe. Thank you all very much!!!', -# thumbnail: 'thumbnail.png' -# } - -# let(:id) { blog.id } -# run_test! -# end - -# response '404', 'blog not found' do -# let(:id) { 'invalid' } -# run_test! -# end -# end -# end - - -# path '/blogs/{id}/upload' do -# let(:id) { blog.id } -# let(:blog) { Blog.create(title: 'foo', content: 'bar') } - -# put 'Uploads a blog thumbnail' do -# parameter name: :id, in: :path, type: :string - -# tags 'Blogs' -# description 'Upload a thumbnail for specific blog by id' -# operationId 'uploadThumbnailBlog' -# consumes 'multipart/form-data' - -# request_body_multipart schema: {properties: {:orderId => { type: :integer }, file: { type: :string, format: :binary }} } - -# response '200', 'blog updated' do -# let(:file) { Rack::Test::UploadedFile.new(Rails.root.join('spec/fixtures/thumbnail.png')) } -# run_test! -# end -# end -# end -# end diff --git a/test-app/swagger/v1/swagger.json b/test-app/swagger/v1/swagger.json index df8d4ba..aa193be 100644 --- a/test-app/swagger/v1/swagger.json +++ b/test-app/swagger/v1/swagger.json @@ -100,20 +100,8 @@ ], "description": "Creates a new blog from provided data", "operationId": "createBlog", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], "parameters": [ - { - "name": "blog", - "in": "body", - "schema": { - "$ref": "#/definitions/blog" - } - } + ], "responses": { "201": { @@ -131,6 +119,15 @@ } } } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/blog" + } + } + } } }, "get": { @@ -140,9 +137,6 @@ ], "description": "Searches blogs by keywords", "operationId": "searchBlogs", - "produces": [ - "application/json" - ], "parameters": [ { "name": "keywords", @@ -179,9 +173,6 @@ ], "description": "Retrieves a specific blog by id", "operationId": "getBlog", - "produces": [ - "application/json" - ], "responses": { "200": { "description": "blog found", @@ -238,18 +229,8 @@ ], "description": "Upload a thumbnail for specific blog by id", "operationId": "uploadThumbnailBlog", - "consumes": [ - "multipart/form-data" - ], "parameters": [ - { - "name": "file", - "in": "formData", - "required": true, - "schema": { - "type": "file" - } - } + ], "responses": { "200": { @@ -257,6 +238,15 @@ "content": { } } + }, + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "file" + } + } + } } } }