diff --git a/lib/grape-swagger/doc_methods.rb b/lib/grape-swagger/doc_methods.rb index 42688030..96c70cd4 100644 --- a/lib/grape-swagger/doc_methods.rb +++ b/lib/grape-swagger/doc_methods.rb @@ -1,3 +1,5 @@ +require 'grape-swagger/doc_methods/status_codes' + require 'grape-swagger/doc_methods/produces_consumes' require 'grape-swagger/doc_methods/data_type' require 'grape-swagger/doc_methods/extensions' @@ -6,7 +8,7 @@ require 'grape-swagger/doc_methods/path_string' require 'grape-swagger/doc_methods/tag_name_description' require 'grape-swagger/doc_methods/parse_params' -# require 'grape-swagger/doc_methods/move_params' +require 'grape-swagger/doc_methods/move_params' module GrapeSwagger module DocMethods diff --git a/lib/grape-swagger/doc_methods/move_params.rb b/lib/grape-swagger/doc_methods/move_params.rb new file mode 100644 index 00000000..d20d1592 --- /dev/null +++ b/lib/grape-swagger/doc_methods/move_params.rb @@ -0,0 +1,119 @@ +module GrapeSwagger + module DocMethods + class MoveParams + class << self + def to_definition(paths, definitions) + @definitions = definitions + find_post_put(paths) do |path| + find_definition_and_parameters(path) + end + end + + def find_post_put(paths) + paths.each do |x| + found = x.last.select { |y| move_methods.include?(y) } + yield found unless found.empty? + end + end + + def find_definition_and_parameters(path) + path.keys.each do |verb| + parameters = path[verb][:parameters] + + next if parameters.nil? + next unless should_move?(parameters) + + unify!(parameters) + + status_code = GrapeSwagger::DocMethods::StatusCodes.get[verb.to_sym][:code] + response = path[verb][:responses][status_code] + referenced_definition = parse_model(response[:schema]['$ref']) + + name = build_definition(verb, referenced_definition) + + move_params_to_new(verb, name, parameters) + @definitions[name].delete(:required) if @definitions[name][:required].empty? + path[verb][:parameters] << build_body_parameter(response.dup, name) + end + end + + def build_definition(verb, name) + name = "#{verb}Request#{name}".to_sym + @definitions[name] = { type: 'object', properties: {}, required: [] } + + name + end + + def move_params_to_new(_, name, parameters) + properties = {} + definition = @definitions[name] + request_parameters = parameters.dup + + request_parameters.each do |param| + next unless movable?(param) + name = param[:name].to_sym + properties[name] = {} + + properties[name].tap do |x| + property_keys.each do |attribute| + x[attribute] = param[attribute] unless param[attribute].nil? + end + end + + properties[name][:readOnly] = true unless deletable?(param) + parameters.delete(param) if deletable?(param) + definition[:required] << name if deletable?(param) && param[:required] + end + + definition[:properties] = properties + end + + def build_body_parameter(response, name = false) + body_param = {} + body_param.tap do |x| + x[:name] = parse_model(response[:schema]['$ref']) + x[:in] = 'body' + x[:required] = true + x[:schema] = { '$ref' => response[:schema]['$ref'] } unless name + x[:schema] = { '$ref' => "#/definitions/#{name}" } if name + end + end + + private + + def unify!(params) + params.each do |param| + param[:in] = param.delete(:param_type) if param.key?(:param_type) + param[:in] = 'body' if param[:in] == 'formData' + end + end + + def parse_model(ref) + ref.split('/').last + end + + def move_methods + [:post, :put, :patch] + end + + def property_keys + [:type, :format, :description, :minimum, :maximum, :items] + end + + def movable?(param) + return true if param[:in] == 'body' || param[:in] == 'path' + false + end + + def deletable?(param) + return true if movable?(param) && param[:in] == 'body' + false + end + + def should_move?(parameters) + !parameters.select { |x| x[:in] == 'body' || x[:param_type] == 'body' }.empty? + end + end + end + end +end diff --git a/lib/grape-swagger/doc_methods/status_codes.rb b/lib/grape-swagger/doc_methods/status_codes.rb new file mode 100644 index 00000000..fc4ec8b9 --- /dev/null +++ b/lib/grape-swagger/doc_methods/status_codes.rb @@ -0,0 +1,17 @@ +module GrapeSwagger + module DocMethods + class StatusCodes + class << self + def get + { + get: { code: 200, message: 'get {item}(s)' }, + post: { code: 201, message: 'created {item}' }, + put: { code: 200, message: 'updated {item}' }, + patch: { code: 200, message: 'patched {item}' }, + delete: { code: 200, message: 'deleted {item}' } + } + end + end + end + end +end diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 6cd95fad..8fe2b595 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -71,8 +71,7 @@ def path_and_definition_objects(namespace_routes, options) end add_definitions_from options[:models] - - # GrapeSwagger::DocMethods::MoveParams.to_definition(@paths, @definitions) + GrapeSwagger::DocMethods::MoveParams.to_definition(@paths, @definitions) [@paths, @definitions] end @@ -151,7 +150,7 @@ def params_object(route) end def response_object(route) - default_code = default_status_codes[route.route_method.downcase.to_sym] + default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.route_method.downcase.to_sym] default_code[:model] = @entity if @entity default_code[:message] = route.route_description || default_code[:message].sub('{item}', @item) @@ -291,16 +290,6 @@ def model_name(name) name.respond_to?(:name) ? name.name.demodulize.camelize : name.split('::').last end - def default_status_codes - { - get: { code: 200, message: 'get {item}(s)' }, - post: { code: 201, message: 'created {item}' }, - put: { code: 200, message: 'updated {item}' }, - patch: { code: 200, message: 'patched {item}' }, - delete: { code: 200, message: 'deleted {item}' } - } - end - def could_it_be_a_model?(value) ( value[:type].to_s.include?('Entity') || value[:type].to_s.include?('Entities') diff --git a/spec/lib/move_params_spec.rb b/spec/lib/move_params_spec.rb new file mode 100644 index 00000000..6109ace4 --- /dev/null +++ b/spec/lib/move_params_spec.rb @@ -0,0 +1,250 @@ +require 'spec_helper' + +describe GrapeSwagger::DocMethods::MoveParams do + include_context "the api paths/defs" + + subject { described_class } + + it { expect(subject.to_s).to eql 'GrapeSwagger::DocMethods::MoveParams' } + + describe 'find_post_put' do + let(:paths) { {} } + + describe 'paths empty' do + specify { expect { |b| subject.find_post_put(paths, &b) }.not_to yield_control } + end + + describe 'no post/put given' do + let(:paths) {{ + :'/foo'=> { get: {}, delete: {}}, + :'/bar/{key}'=> { get: {}, delete: {}}, + }} + specify { expect { |b| subject.find_post_put(paths, &b) }.not_to yield_control } + end + + describe 'no post/put given' do + let(:paths) {{ + :'/foo'=> { get: {}, delete: {}, post: {}, put: {}, patch: {} }, + :'/bar/{key}'=> { get: {}, delete: {}, post: {}, put: {}, patch: {}}, + }} + let(:expected) {[ + { post: {}, put: {}, patch: {}}, + { post: {}, put: {}, patch: {}}, + ]} + specify { expect { |b| subject.find_post_put(paths, &b) }.to yield_control.twice } + specify { expect { |b| subject.find_post_put(paths, &b) }.to yield_successive_args *expected } + end + end + + describe 'build_definition' do + let(:verb) { 'post' } + let(:name) { 'Foo' } + let(:definitions) {{}} + + specify do + subject.instance_variable_set(:@definitions, definitions) + subject.build_definition(verb, name) + + definition = definitions.to_a.first + expect(definition.first).to eql :postRequestFoo + expect(definition.last).to eql({ type: 'object', properties: {}, required: [] }) + end + end + + describe 'move_params_to_new definition' do + let(:name) { 'Foo' } + let(:definitions) {{}} + + describe 'post request' do + let(:verb) { 'post' } + let(:params) { paths["/in_body"][:post][:parameters] } + + specify do + subject.instance_variable_set(:@definitions, definitions) + name = subject.build_definition(verb, name) + subject.move_params_to_new(verb, name, params) + + expect(definitions[name]).to eql expected_post_defs + expect(params).to be_empty + end + end + + describe 'put request' do + let(:verb) { 'put' } + let(:params) { paths["/in_body/{key}"][:put][:parameters] } + + specify do + subject.instance_variable_set(:@definitions, definitions) + name, definition = subject.build_definition(verb, name) + subject.move_params_to_new(verb, name, params) + + expect(definitions[name]).to eql expected_put_defs + expect(params.length).to be 1 + end + end + end + + describe 'find_definition' do + specify do + subject.instance_variable_set(:@definitions, definitions) + subject.find_definition_and_parameters(found_path) + + expect(definitions.keys).to include 'InBody', :postRequestInBody + end + end + + describe 'build_body_parameter' do + let(:response) {{ schema: { '$ref' => '#/definitions/Somewhere'} }} + + describe 'no name given' do + let(:expected_param) { + {:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/Somewhere"}} + } + specify do + parameter = subject.build_body_parameter(response) + expect(parameter).to eql expected_param + end + end + + describe 'name given' do + let(:name) { 'Foo' } + let(:expected_param) { + {:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/#{name}"}} + } + specify do + parameter = subject.build_body_parameter(response, name) + expect(parameter).to eql expected_param + end + end + end + + describe 'private methods' do + describe 'parse_model' do + let(:ref) { '#/definitions/InBody' } + subject(:object) { described_class.send(:parse_model, ref) } + + specify { expect(object).to eql 'InBody' } + end + + describe 'movable' do + describe 'path' do + let(:param) {{ in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }} + it { expect(subject.send(:movable?, param)).to be true } + end + + describe 'body' do + let(:param) {{ in: "body", name: "in_body", description: "in_body", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:movable?, param)).to be true } + end + + describe 'query' do + let(:param) {{ in: "query", name: "in_query", description: "in_query", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:movable?, param)).to be false } + end + + describe 'header' do + let(:param) {{ in: "header", name: "in_header", description: "in_header", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:movable?, param)).to be false } + end + end + + describe 'deletable' do + describe 'path' do + let(:param) {{ in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }} + it { expect(subject.send(:deletable?, param)).to be false } + end + + describe 'body' do + let(:param) {{ in: "body", name: "in_body_1", description: "in_body_1", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:deletable?, param)).to be true } + end + + describe 'query' do + let(:param) {{ in: "query", name: "in_query_1", description: "in_query_1", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:deletable?, param)).to be false } + end + + describe 'header' do + let(:param) {{ in: "header", name: "in_header_1", description: "in_header_1", type: "integer", format: "int32", required: true }} + it { expect(subject.send(:deletable?, param)).to be false } + end + end + + describe 'should move' do + describe 'no move' do + let(:params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + it { expect(subject.send(:should_move?, params)).to be false } + end + + describe 'move' do + let(:params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "body", name: "in_bosy", description: "in_bosy", type: "integer", format: "int32", required: true }, + { in: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + it { expect(subject.send(:should_move?, params)).to be true } + end + end + + describe 'unify' do + before do + subject.send(:unify!, params) if subject.send(:should_move?, params) + end + describe 'param type with `:in` given' do + let(:params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "body", name: "in_body", description: "in_body", type: "integer", format: "int32", required: true }, + { in: "query", name: "in_query", description: "in_query", type: "integer", format: "int32", required: true }, + { in: "header", name: "in_header", description: "in_header", type: "integer", format: "int32", required: true }, + { in: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + + let(:expected_params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "body", name: "in_body", description: "in_body", type: "integer", format: "int32", required: true }, + { in: "query", name: "in_query", description: "in_query", type: "integer", format: "int32", required: true }, + { in: "header", name: "in_header", description: "in_header", type: "integer", format: "int32", required: true }, + { in: "body", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + it { expect(params).to eql expected_params } + end + + describe 'let it as is' do + let(:params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + + let(:expected_params) {[ + { in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { in: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + it { expect(params).to eql expected_params } + + end + + describe 'param type with `:param_type` given' do + let(:params) {[ + { param_type: "path", name: "key", description: nil, type: "integer", format: "int32", required: true }, + { param_type: "body", name: "in_body", description: "in_body", type: "integer", format: "int32", required: true }, + { param_type: "query", name: "in_query", description: "in_query", type: "integer", format: "int32", required: true }, + { param_type: "header", name: "in_header", description: "in_header", type: "integer", format: "int32", required: true }, + { param_type: "formData", name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true } + ]} + + let(:expected_params) {[ + { name: "key", description: nil, type: "integer", format: "int32", required: true, in: "path" }, + { name: "in_body", description: "in_body", type: "integer", format: "int32", required: true, in: "body" }, + { name: "in_query", description: "in_query", type: "integer", format: "int32", required: true, in: "query" }, + { name: "in_header", description: "in_header", type: "integer", format: "int32", required: true, in: "header" }, + { name: "in_form_data", description: "in_form_data", type: "integer", format: "int32", required: true, in: "body" } + ]} + it { expect(params).to eql expected_params } + end + end + + end +end diff --git a/spec/support/the_api_entities.rb b/spec/support/the_api_entities.rb index 4d369b59..9b710c64 100644 --- a/spec/support/the_api_entities.rb +++ b/spec/support/the_api_entities.rb @@ -28,10 +28,22 @@ class UseResponse < Grape::Entity expose :items, as: '$responses', using: Entities::ResponseItem, documentation: { is_array: true } end - class UseTemResponseAsType < Grape::Entity + class UseItemResponseAsType < Grape::Entity expose :description, documentation: { type: String } expose :responses, documentation: { type: Entities::ResponseItem, is_array: false } end + + class UseAddress < Grape::Entity + expose :street, documentation: { type: String, desc: 'street' } + expose :postcode, documentation: { type: String, desc: 'postcode' } + expose :city, documentation: { type: String, desc: 'city' } + expose :country, documentation: { type: String, desc: 'country' } + end + + class UseNestedWithAddress < Grape::Entity + expose :name, documentation: { type: String } + expose :address, using: Entities::UseAddress + end end end end diff --git a/spec/support/the_paths_definitions.rb b/spec/support/the_paths_definitions.rb new file mode 100644 index 00000000..f424b1ed --- /dev/null +++ b/spec/support/the_paths_definitions.rb @@ -0,0 +1,94 @@ +RSpec.shared_context "the api paths/defs" do + let(:paths) {{ + "/in_body" => { + post: { + produces: ["application/json"], + consumes: ["application/json"], + parameters: [ + {in: "body", name: "in_body_1", description: "in_body_1", type: "integer", format: "int32", required: true}, + {in: "body", name: "in_body_2", description: "in_body_2", type: "string", required: false}, + {in: "body", name: "in_body_3", description: "in_body_3", type: "string", required: false} + ], + responses: {201 => {description: "post in body /wo entity", schema: {"$ref" => "#/definitions/InBody"}}}, + tags: ["in_body"], + operationId: "postInBody" + }, + get: { + produces: ["application/json"], + responses: {200 => {description: "get in path /wo entity", schema: {"$ref" => "#/definitions/InBody"}}}, + tags: ["in_body"], + operationId: "getInBody" + } + }, + "/in_body/{key}" => { + put: { + produces: ["application/json"], + consumes: ["application/json"], + parameters: [ + {in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true}, + {in: "body", name: "in_body_1", description: "in_body_1", type: "integer", format: "int32", required: true}, + {in: "body", name: "in_body_2", description: "in_body_2", type: "string", required: false}, + {in: "body", name: "in_body_3", description: "in_body_3", type: "string", required: false} + ], + responses: {200 => {description: "put in body /wo entity", schema: {"$ref" => "#/definitions/InBody"}}}, + tags: ["in_body"], + operationId: "putInBodyKey" + }, + get: { + produces: ["application/json"], + parameters: [ + {in: "path", name: "key", description: nil, type: "integer", format: "int32", required: true} + ], + responses: {200 => {description: "get in path /wo entity", schema: {"$ref" => "#/definitions/InBody"}}}, + tags: ["in_body"], + operationId: "getInBodyKey" + }} + }} + + let(:found_path) {{ + post: { + produces: ["application/json"], + consumes: ["application/json"], + parameters: [ + {in: "body", name: "in_body_1", description: "in_body_1", type: "integer", format: "int32", required: true}, + {in: "body", name: "in_body_2", description: "in_body_2", type: "string", required: false}, + {in: "body", name: "in_body_3", description: "in_body_3", type: "string", required: false} + ], + responses: {201 => {description: "post in body /wo entity", schema: {"$ref"=>"#/definitions/InBody"}}}, + tags: ["in_body"], + operationId: "postInBody" + }}} + + let(:definitions) {{ + "InBody" => { + type: "object", + properties: { + in_body_1: {type: "integer", format: "int32"}, + in_body_2: {type: "string"}, + in_body_3: {type: "string"}, + key: {type: "integer", format: "int32"} + }}}} + + let(:expected_post_defs) {{ + type: "object", + properties: { + in_body_1: {type: "integer", format: "int32", description: "in_body_1"}, + in_body_2: {type: "string", description: "in_body_2"}, + in_body_3: {type: "string", description: "in_body_3"} + }, + :required=>[:in_body_1] + }} + + let(:expected_put_defs) {{ + type: "object", + properties: { + in_body_1: {type: "integer", format: "int32", description: "in_body_1"}, + in_body_2: {type: "string", description: "in_body_2"}, + in_body_3: {type: "string", description: "in_body_3"}, + key: {type: "integer", format: "int32", readOnly: true} + }, + :required=>[:in_body_1] + }} + + let(:expected_path) {[]} +end diff --git a/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb b/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb new file mode 100644 index 00000000..b2e8fc76 --- /dev/null +++ b/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb @@ -0,0 +1,193 @@ +require 'spec_helper' + +describe 'setting of param type, such as `query`, `path`, `formData`, `body`, `header`' do + include_context "the api entities" + + before :all do + module TheApi + class BodyParamTypeApi < Grape::API + namespace :wo_entities do + desc 'post in body /wo entity' + params do + requires :in_body_1, type: Integer, documentation: { desc: 'in_body_1', param_type: 'body' } + optional :in_body_2, type: String, documentation: { desc: 'in_body_2', param_type: 'body' } + optional :in_body_3, type: String, documentation: { desc: 'in_body_3', param_type: 'body' } + end + + post '/in_body' do + { "declared_params" => declared(params) } + end + + desc 'put in body /wo entity' + params do + requires :key, type: Integer + optional :in_body_1, type: Integer, documentation: { desc: 'in_body_1', param_type: 'body' } + optional :in_body_2, type: String, documentation: { desc: 'in_body_2', param_type: 'body' } + optional :in_body_3, type: String, documentation: { desc: 'in_body_3', param_type: 'body' } + end + + put '/in_body/:key' do + { "declared_params" => declared(params) } + end + end + + namespace :with_entities do + desc 'post in body with entity', + success: TheApi::Entities::ResponseItem + params do + requires :name, type: String, documentation: { desc: 'name', param_type: 'body' } + end + + post '/in_body' do + { "declared_params" => declared(params) } + end + + desc 'put in body with entity', + success: TheApi::Entities::ResponseItem + params do + requires :id, type: Integer + optional :name, type: String, documentation: { desc: 'name', param_type: 'body' } + end + + put '/in_body/:id' do + { "declared_params" => declared(params) } + end + end + + # namespace :nested_params do + # desc 'post in body with entity', + # success: TheApi::Entities::UseNestedWithAddress + # params do + # requires :name, type: String, documentation: { desc: 'name', in: 'body' } + # optional :address, type: Hash do + # requires :street, type: String, documentation: { desc: 'street', in: 'body' } + # requires :postcode, type: String, documentation: { desc: 'postcode', in: 'body' } + # requires :city, type: String, documentation: { desc: 'city', in: 'body' } + # optional :country, type: String, documentation: { desc: 'country', in: 'body' } + # end + # end + # + # post '/in_body' do + # { "declared_params" => declared(params) } + # end + # + # desc 'put in body with entity', + # success: TheApi::Entities::UseNestedWithAddress + # params do + # requires :id, type: Integer + # optional :name, type: String, documentation: { desc: 'name', in: 'body' } + # optional :address, type: Hash do + # optional :street, type: String, documentation: { desc: 'street', in: 'body' } + # optional :postcode, type: String, documentation: { desc: 'postcode', in: 'formData' } + # optional :city, type: String, documentation: { desc: 'city', in: 'body' } + # optional :country, type: String, documentation: { desc: 'country', in: 'body' } + # end + # end + # + # put '/in_body/:id' do + # { "declared_params" => declared(params) } + # end + # end + + add_swagger_documentation + end + end + end + + def app + TheApi::BodyParamTypeApi + end + + describe 'no entity given' do + subject do + get '/swagger_doc/wo_entities' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/wo_entities/in_body']['post']['parameters']).to eql([ + {"name"=>"InBody", "in"=>"body", "required"=>true, "schema"=>{"$ref"=>"#/definitions/postRequestInBody"}} + ]) + end + + specify do + expect(subject['definitions']['postRequestInBody']).to eql({ + "type"=>"object", + "properties"=>{ + "in_body_1"=>{"type"=>"integer", "format"=>"int32", "description"=>"in_body_1"}, + "in_body_2"=>{"type"=>"string", "description"=>"in_body_2"}, + "in_body_3"=>{"type"=>"string", "description"=>"in_body_3"} + }, + "required"=>["in_body_1"] + }) + end + + specify do + expect(subject['paths']['/wo_entities/in_body/{key}']['put']['parameters']).to eql([ + {"in"=>"path", "name"=>"key", "description"=>nil, "type"=>"integer", "format"=>"int32", "required"=>true}, + {"name"=>"InBody", "in"=>"body", "required"=>true, "schema"=>{"$ref"=>"#/definitions/putRequestInBody"}} + ]) + end + + specify do + expect(subject['definitions']['putRequestInBody']).to eql({ + "type"=>"object", + "properties"=>{ + "key"=>{"type"=>"integer", "format"=>"int32", "readOnly"=>true}, + "in_body_1"=>{"type"=>"integer", "format"=>"int32", "description"=>"in_body_1"}, + "in_body_2"=>{"type"=>"string", "description"=>"in_body_2"}, + "in_body_3"=>{"type"=>"string", "description"=>"in_body_3"} + } + }) + end + end + + describe 'entity given' do + subject do + get '/swagger_doc/with_entities' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/with_entities/in_body']['post']['parameters']).to eql([ + {"name"=>"ResponseItem", "in"=>"body", "required"=>true, "schema"=>{"$ref"=>"#/definitions/postRequestResponseItem"}} + ]) + end + + specify do + expect(subject['definitions']['postRequestResponseItem']).to eql({ + "type"=>"object", + "properties"=>{ + "name"=>{"type"=>"string", "description"=>"name"}}, + "required"=>["name"] + }) + end + + specify do + expect(subject['paths']['/with_entities/in_body/{id}']['put']['parameters']).to eql([ + {"in"=>"path", "name"=>"id", "description"=>nil, "type"=>"integer", "format"=>"int32", "required"=>true}, + {"name"=>"ResponseItem", "in"=>"body", "required"=>true, "schema"=>{"$ref"=>"#/definitions/putRequestResponseItem"}} + ]) + end + + specify do + expect(subject['definitions']['putRequestResponseItem']).to eql({ + "type"=>"object", + "properties"=>{ + "id"=>{"type"=>"integer", "format"=>"int32", "readOnly"=>true}, + "name"=>{"type"=>"string", "description"=>"name"}} + }) + end + end + + # describe 'nested body parameters given' do + # subject do + # get '/swagger_doc/nested_params' + # JSON.parse(last_response.body) + # end + # + # specify do + # # ap subject + # end + # end +end diff --git a/spec/swagger_v2/api_swagger_v2_response_spec.rb b/spec/swagger_v2/api_swagger_v2_response_spec.rb index 685ce9f8..10e7f4ec 100644 --- a/spec/swagger_v2/api_swagger_v2_response_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_response_spec.rb @@ -23,7 +23,7 @@ class ResponseApi < Grape::API end desc 'This returns something', - entity: Entities::UseTemResponseAsType, + entity: Entities::UseItemResponseAsType, failure: [{code: 400, message: 'NotFound', model: Entities::ApiError}] get '/nested_type' do { "declared_params" => declared(params) } @@ -61,7 +61,7 @@ def app "get"=>{ "produces"=>["application/json"], "responses"=>{ - "200"=>{"description"=>"This returns something", "schema"=>{"$ref"=>"#/definitions/UseTemResponseAsType"}}, + "200"=>{"description"=>"This returns something", "schema"=>{"$ref"=>"#/definitions/UseItemResponseAsType"}}, "400"=>{"description"=>"NotFound", "schema"=>{"$ref"=>"#/definitions/ApiError"}} }, "tags"=>["nested_type"], @@ -69,7 +69,7 @@ def app }}}, "definitions"=>{ "ResponseItem"=>{"type"=>"object", "properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "name"=>{"type"=>"string"}}}, - "UseTemResponseAsType"=>{"type"=>"object", "properties"=>{"description"=>{"type"=>"string"}, "responses"=>{"$ref"=>"#/definitions/ResponseItem"}}}, + "UseItemResponseAsType"=>{"type"=>"object", "properties"=>{"description"=>{"type"=>"string"}, "responses"=>{"$ref"=>"#/definitions/ResponseItem"}}}, "ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer", "format"=>"int32"}, "message"=>{"type"=>"string"}}} }}) end