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