Response model can have required attributes (#521)
* Response model can have required attributes * Reorganize implementation * Fix RuboCop offences * Last touch of refactor
This commit is contained in:
		
							parent
							
								
									d7b7465a95
								
							
						
					
					
						commit
						7061fd1b75
					
				|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| #### Features | #### Features | ||||||
| 
 | 
 | ||||||
|  | * [#520](https://github.com/ruby-grape/grape-swagger/pull/520): Response model can have required attributes - [@WojciechKo](https://github.com/WojciechKo). | ||||||
| * [#510](https://github.com/ruby-grape/grape-swagger/pull/510): Use 'token_owner' instead of 'oauth_token' on Swagger UI endpoint authorization. - [@texpert](https://github.com/texpert). | * [#510](https://github.com/ruby-grape/grape-swagger/pull/510): Use 'token_owner' instead of 'oauth_token' on Swagger UI endpoint authorization. - [@texpert](https://github.com/texpert). | ||||||
| * Your contribution here. | * Your contribution here. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -849,14 +849,14 @@ route_setting :x_def, [{ for: 422, other: 'stuff' }, { for: 200, some: 'stuff' } | ||||||
| 
 | 
 | ||||||
| Add the [grape-entity](https://github.com/ruby-grape/grape-entity) and [grape-swagger-entity](https://github.com/ruby-grape/grape-swagger-entity) gem to your Gemfile. | Add the [grape-entity](https://github.com/ruby-grape/grape-entity) and [grape-swagger-entity](https://github.com/ruby-grape/grape-swagger-entity) gem to your Gemfile. | ||||||
| 
 | 
 | ||||||
| The following example exposes statuses. And exposes statuses documentation adding :type and :desc. | The following example exposes statuses. And exposes statuses documentation adding :type, :desc and :required. | ||||||
| The documented class/definition name could be set via `#entity_name`. | The documented class/definition name could be set via `#entity_name`. | ||||||
| 
 | 
 | ||||||
| ```ruby | ```ruby | ||||||
| module API | module API | ||||||
|   module Entities |   module Entities | ||||||
|     class Status < Grape::Entity |     class Status < Grape::Entity | ||||||
|       expose :text, documentation: { type: 'string', desc: 'Status update text.' } |       expose :text, documentation: { type: 'string', desc: 'Status update text.', required: true } | ||||||
|       expose :links, using: Link, documentation: { type: 'link', is_array: true } |       expose :links, using: Link, documentation: { type: 'link', is_array: true } | ||||||
|       expose :numbers, documentation: { type: 'integer', desc: 'favourite number', values: [1,2,3,4] } |       expose :numbers, documentation: { type: 'integer', desc: 'favourite number', values: [1,2,3,4] } | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ require 'grape-swagger/doc_methods/tag_name_description' | ||||||
| require 'grape-swagger/doc_methods/parse_params' | require 'grape-swagger/doc_methods/parse_params' | ||||||
| require 'grape-swagger/doc_methods/move_params' | require 'grape-swagger/doc_methods/move_params' | ||||||
| require 'grape-swagger/doc_methods/headers' | require 'grape-swagger/doc_methods/headers' | ||||||
|  | require 'grape-swagger/doc_methods/build_model_definition' | ||||||
| 
 | 
 | ||||||
| module GrapeSwagger | module GrapeSwagger | ||||||
|   module DocMethods |   module DocMethods | ||||||
|  |  | ||||||
|  | @ -0,0 +1,38 @@ | ||||||
|  | module GrapeSwagger | ||||||
|  |   module DocMethods | ||||||
|  |     class BuildModelDefinition | ||||||
|  |       class << self | ||||||
|  |         def build(model, properties) | ||||||
|  |           definition = { type: 'object', properties: properties } | ||||||
|  | 
 | ||||||
|  |           required = required_attributes(model) | ||||||
|  |           definition[:required] = required unless required.blank? | ||||||
|  | 
 | ||||||
|  |           definition | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private | ||||||
|  | 
 | ||||||
|  |         def required_attributes(model) | ||||||
|  |           parse_entity(model) || parse_representable(model) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         def parse_entity(model) | ||||||
|  |           return unless model.respond_to?(:documentation) | ||||||
|  | 
 | ||||||
|  |           model.documentation | ||||||
|  |                .select { |_name, options| options[:required] } | ||||||
|  |                .map { |name, options| options[:as] || name } | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         def parse_representable(model) | ||||||
|  |           return unless model.respond_to?(:map) | ||||||
|  | 
 | ||||||
|  |           model.map | ||||||
|  |                .select { |p| p[:documentation] && p[:documentation][:required] } | ||||||
|  |                .map(&:name) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -291,7 +291,7 @@ module Grape | ||||||
|       properties = parser.new(model, self).call |       properties = parser.new(model, self).call | ||||||
|       raise GrapeSwagger::Errors::SwaggerSpec, "Empty model #{model_name}, swagger 2.0 doesn't support empty definitions." unless properties && properties.any? |       raise GrapeSwagger::Errors::SwaggerSpec, "Empty model #{model_name}, swagger 2.0 doesn't support empty definitions." unless properties && properties.any? | ||||||
| 
 | 
 | ||||||
|       @definitions[model_name] = { type: 'object', properties: properties } |       @definitions[model_name] = GrapeSwagger::DocMethods::BuildModelDefinition.build(model, properties) | ||||||
| 
 | 
 | ||||||
|       model_name |       model_name | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -304,11 +304,13 @@ RSpec.shared_context 'entity swagger example' do | ||||||
|       'definitions' => { |       'definitions' => { | ||||||
|         'QueryInput' => { |         'QueryInput' => { | ||||||
|           'type' => 'object', |           'type' => 'object', | ||||||
|  |           'required' => ['elements'], | ||||||
|           'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } }, |           'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } }, | ||||||
|           'description' => 'nested route inside namespace' |           'description' => 'nested route inside namespace' | ||||||
|         }, |         }, | ||||||
|         'QueryInputElement' => { |         'QueryInputElement' => { | ||||||
|           'type' => 'object', |           'type' => 'object', | ||||||
|  |           'required' => %w(key value), | ||||||
|           'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } } |           'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } } | ||||||
|         }, |         }, | ||||||
|         'ApiError' => { |         'ApiError' => { | ||||||
|  |  | ||||||
|  | @ -376,11 +376,13 @@ RSpec.shared_context 'representable swagger example' do | ||||||
|       'definitions' => { |       'definitions' => { | ||||||
|         'QueryInput' => { |         'QueryInput' => { | ||||||
|           'type' => 'object', |           'type' => 'object', | ||||||
|  |           'required' => ['elements'], | ||||||
|           'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } }, |           'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } }, | ||||||
|           'description' => 'nested route inside namespace' |           'description' => 'nested route inside namespace' | ||||||
|         }, |         }, | ||||||
|         'QueryInputElement' => { |         'QueryInputElement' => { | ||||||
|           'type' => 'object', |           'type' => 'object', | ||||||
|  |           'required' => %w(key value), | ||||||
|           'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } } |           'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } } | ||||||
|         }, |         }, | ||||||
|         'ApiError' => { |         'ApiError' => { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue