Skip to content

Commit

Permalink
adds format to definition property type
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Scholz committed Mar 25, 2016
1 parent 8d6d04a commit 168146d
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 141 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ env:
- GRAPE_VERSION=0.12.0
- GRAPE_VERSION=0.13.0
- GRAPE_VERSION=0.14.0
- GRAPE_VERSION=HEAD
# - GRAPE_VERSION=HEAD
35 changes: 27 additions & 8 deletions lib/grape-swagger/doc_methods/data_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ def call(value)
raw_data_type = value[:type] if value.is_a?(Hash)
raw_data_type ||= 'string'
case raw_data_type.to_s
when 'Boolean', 'Date', 'Integer', 'String', 'Float', 'JSON', 'Array'
raw_data_type.to_s.downcase
when 'Hash'
'object'
when 'Rack::Multipart::UploadedFile'
'File'
when 'Rack::Multipart::UploadedFile', 'File'
'file'
when 'Virtus::Attribute::Boolean'
'boolean'
when 'Boolean', 'Date', 'Integer', 'String', 'Float'
raw_data_type.to_s.downcase
when 'BigDecimal'
'long'
when 'DateTime'
'double'
when 'DateTime', 'Time'
'dateTime'
when 'Numeric'
'double'
'long'
when 'Symbol'
'string'
else
Expand All @@ -37,6 +37,22 @@ def parse_entity_name(model)
entity_parts.join('::')
end
end

def request_primitive?(type)
request_primitives.include?(type.to_s.downcase)
end

def primitive?(type)
primitives.include?(type.to_s.downcase)
end

def request_primitives
primitives + %w(object string boolean file json array)
end

def primitives
PRIMITIVE_MAPPINGS.keys.map(&:downcase)
end
end

PRIMITIVE_MAPPINGS = {
Expand All @@ -46,7 +62,10 @@ def parse_entity_name(model)
'double' => %w(number double),
'byte' => %w(string byte),
'date' => %w(string date),
'dateTime' => %w(string date-time)
'dateTime' => %w(string date-time),
'binary' => %w(string binary),
'password' => %w(string password),
'email' => %w(string email)
}.freeze
end
end
Expand Down
39 changes: 18 additions & 21 deletions lib/grape-swagger/doc_methods/parse_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ def call(param, value, route)
path = route.route_path
method = route.route_method

additional_documentation = value.is_a?(Hash) ? value[:documentation] : nil
data_type = GrapeSwagger::DocMethods::DataType.call(value)

if additional_documentation && value.is_a?(Hash)
additional_documentation = value[:documentation]
if additional_documentation
value = additional_documentation.merge(value)
end

description = value.is_a?(Hash) ? value[:desc] || value[:description] : nil
required = value.is_a?(Hash) ? value[:required] : false
default_value = value.is_a?(Hash) ? value[:default] : nil
example = value.is_a?(Hash) ? value[:example] : nil
is_array = value.is_a?(Hash) ? (value[:is_array] || false) : false
values = value.is_a?(Hash) ? value[:values] : nil
name = (value.is_a?(Hash) && value[:full_name]) || param
description = value[:desc] || value[:description] || nil
required = value[:required] || false
default_value = value[:default] || nil
example = value[:example] || nil
is_array = value[:is_array] || false
values = value[:values] || nil
name = value[:full_name] || param
enum_or_range_values = parse_enum_or_range_values(values)

value_type = { value: value, data_type: data_type, path: path }
Expand All @@ -29,31 +28,29 @@ def call(param, value, route)
in: param_type(value_type, param, method, is_array),
name: name,
description: description,
type: data_type,
required: required
}

if GrapeSwagger::DocMethods::DataType::PRIMITIVE_MAPPINGS.key?(data_type)
parsed_params[:type], parsed_params[:format] = GrapeSwagger::DocMethods::DataType::PRIMITIVE_MAPPINGS[data_type]
if GrapeSwagger::DocMethods::DataType.primitive?(data_type)
data = GrapeSwagger::DocMethods::DataType::PRIMITIVE_MAPPINGS[data_type]
parsed_params[:type], parsed_params[:format] = data
else
parsed_params[:type] = data_type
end

parsed_params[:items] = @array_items if @array_items.present?

parsed_params[:defaultValue] = example if example
parsed_params[:defaultValue] = default_value if default_value && example.blank?
parsed_params[:default] = example if example
parsed_params[:default] = default_value if default_value && example.blank?

parsed_params.merge!(enum_or_range_values) if enum_or_range_values
parsed_params
end

def primitive?(type)
%w(object integer long float double string byte boolean date datetime).include? type.to_s.downcase
end

private

def param_type(value_type, param, method, is_array)
# TODO: use `value_type.dig():value, :documentation, :param_type)` instead req ruby2.3
# TODO: use `value_type.dig():value, :documentation, :param_type)` instead, req ruby2.3
#
if value_type[:value].is_a?(Hash) &&
value_type[:value].key?(:documentation) &&
Expand All @@ -69,7 +66,7 @@ def param_type(value_type, param, method, is_array)
when value_type[:path].include?("{#{param}}")
'path'
when %w(POST PUT PATCH).include?(method)
primitive?(value_type[:data_type]) ? 'formData' : 'body'
GrapeSwagger::DocMethods::DataType.request_primitive?(value_type[:data_type]) ? 'formData' : 'body'
else
'query'
end
Expand Down
13 changes: 11 additions & 2 deletions lib/grape-swagger/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,16 @@ def parse_response_params(params)
{ '$ref' => "#/definitions/#{name}" }
end
else
memo[x.first] = { type: GrapeSwagger::DocMethods::DataType.call(x.last[:documentation] || x.last) }

data_type = GrapeSwagger::DocMethods::DataType.call(x.last[:documentation] || x.last)

if GrapeSwagger::DocMethods::DataType.primitive?(data_type)
data = GrapeSwagger::DocMethods::DataType::PRIMITIVE_MAPPINGS[data_type]
memo[x.first] = { type: data.first, format: data.last }
else
memo[x.first] = { type: data_type }
end

memo[x.first][:enum] = x.last[:values] if x.last[:values] && x.last[:values].is_a?(Array)
end
end
Expand Down Expand Up @@ -269,7 +278,7 @@ def could_it_be_a_model?(value)
) || (
value[:type] &&
value[:type].is_a?(Class) &&
!GrapeSwagger::DocMethods::ParseParams.primitive?(value[:type].name.downcase) &&
!GrapeSwagger::DocMethods::DataType.primitive?(value[:type].name.downcase) &&
!value[:type] == Array
)
end
Expand Down
6 changes: 3 additions & 3 deletions spec/lib/data_type_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
describe "Rack::Multipart::UploadedFile" do
let(:value) { { type: Rack::Multipart::UploadedFile } }

it { expect(subject).to eql 'File' }
it { expect(subject).to eql 'file' }
end

describe "Virtus::Attribute::Boolean" do
Expand All @@ -34,7 +34,7 @@
describe "BigDecimal" do
let(:value) { { type: BigDecimal } }

it { expect(subject).to eql 'long' }
it { expect(subject).to eql 'double' }
end

describe "DateTime" do
Expand All @@ -46,7 +46,7 @@
describe "Numeric" do
let(:value) { { type: Numeric } }

it { expect(subject).to eql 'double' }
it { expect(subject).to eql 'long' }
end

describe "Symbol" do
Expand Down
188 changes: 93 additions & 95 deletions spec/support/api_swagger_v2_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,104 +67,102 @@ class ApiError < Grape::Entity
"termsOfServiceUrl"=>"www.The-URL-of-the-terms-and-service.com",
"contact"=>{"name"=>"Contact name", "email"=>"Contact@email.com", "url"=>"Contact URL"},
"license"=>{"name"=>"The name of the license.", "url"=>"www.The-URL-of-the-license.org"},
"version"=>"v1"
},
"swagger"=>"2.0",
"produces"=>["application/json"],
"host"=>"example.org",
"basePath"=>"/api",
"tags"=>[{"name"=>"other_thing", "description"=>"Operations about other_things"},
{"name"=>"thing", "description"=>"Operations about things"},
{"name"=>"thing2", "description"=>"Operations about thing2s"},
{"name"=>"dummy", "description"=>"Operations about dummies"}],
"schemes"=>["https", "http"],
"paths"=>{
"/v3/other_thing/{elements}"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[
{"in"=>"array", "name"=>"elements", "description"=>"Set of configuration", "type"=>"string", "required"=>true, "items"=>{"type"=>"string"}}],
"version"=>"v1"},
"swagger"=>"2.0",
"produces"=>["application/json"],
"host"=>"example.org",
"basePath"=>"/api",
"tags"=>[
{"name"=>"other_thing", "description"=>"Operations about other_things"},
{"name"=>"thing", "description"=>"Operations about things"},
{"name"=>"thing2", "description"=>"Operations about thing2s"},
{"name"=>"dummy", "description"=>"Operations about dummies"}
],
"schemes"=>["https", "http"],
"paths"=>{
"/v3/other_thing/{elements}"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"array", "name"=>"elements", "description"=>"Set of configuration", "required"=>true, "type"=>"string", "items"=>{"type"=>"string"}}],
"responses"=>{"200"=>{"description"=>"nested route inside namespace", "schema"=>{"$ref"=>"#/definitions/QueryInput"}}},
"tags"=>["other_thing"],
"operationId"=>"getV3OtherThingElements",
"responses"=>{"200"=>{"description"=>"nested route inside namespace", "schema"=>{"$ref"=>"#/definitions/QueryInput"}}},
"x-amazon-apigateway-auth"=>{"type"=>"none"},
"x-amazon-apigateway-integration"=>{"type"=>"aws", "uri"=>"foo_bar_uri", "httpMethod"=>"get"}}},
"/thing"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[
{"in"=>"query", "name"=>"id", "description"=>"Identity of Something", "type"=>"integer", "required"=>false, "format"=>"int32"},
{"in"=>"query", "name"=>"text", "description"=>"Content of something.", "type"=>"string", "required"=>false},
{"in"=>"query", "name"=>"links", "description"=>nil, "type"=>"link", "required"=>false},
{"in"=>"query", "name"=>"others", "description"=>nil, "type"=>"text", "required"=>false}],
"tags"=>["thing"],
"operationId"=>"getThing",
"responses"=>{
"200"=>{"description"=>"This gets Things.", "schema"=>{"$ref"=>"#/definitions/Thing"}},
"401"=>{"description"=>"Unauthorized", "schema"=>{"$ref"=>"#/definitions/ApiError"}}}},
"post"=>{
"produces"=>["application/json"],
"consumes"=>["application/json"],
"parameters"=>[
{"in"=>"formData", "name"=>"text", "description"=>"Content of something.", "type"=>"string", "required"=>true},
{"in"=>"body", "name"=>"links", "description"=>nil, "type"=>"Array", "required"=>true}],
"tags"=>["thing"],
"operationId"=>"postThing",
"responses"=>{
"201"=>{"description"=>"This creates Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}},
"422"=>{"description"=>"Unprocessible Entity"}}
}},
"/thing/{id}"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[
{"in"=>"path", "name"=>"id", "description"=>nil, "type"=>"integer", "required"=>true, "format"=>"int32"}],
"tags"=>["thing"],
"operationId"=>"getThingId",
"responses"=>{
"200"=>{"description"=>"getting a single thing", "schema"=>{"$ref"=>"#/definitions/Thing"}},
"401"=>{"description"=>"Unauthorized"}}},
"put"=>{
"produces"=>["application/json"],
"consumes"=>["application/json"],
"parameters"=>[
{"in"=>"path", "name"=>"id", "description"=>nil, "type"=>"integer", "required"=>true, "format"=>"int32"},
{"in"=>"formData", "name"=>"text", "description"=>"Content of something.", "type"=>"string", "required"=>false},
{"in"=>"body", "name"=>"links", "description"=>nil, "type"=>"Array", "required"=>false}],
"tags"=>["thing"],
"operationId"=>"putThingId",
"responses"=>{"200"=>{"description"=>"This updates Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}}}},
"delete"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "type"=>"integer", "required"=>true, "format"=>"int32"}],
"tags"=>["thing"],
"operationId"=>"deleteThingId",
"responses"=>{"200"=>{"description"=>"This deletes Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}}}
}},
"/thing2"=>{
"get"=>{
"produces"=>["application/json"],
"tags"=>["thing2"],
"operationId"=>"getThing2",
"responses"=>{
"200"=>{"description"=>"get Horses", "schema"=>{"$ref"=>"#/definitions/Something"}},
"401"=>{"description"=>"HorsesOutError", "schema"=>{"$ref"=>"#/definitions/ApiError"}}}
}},
"/dummy/{id}"=>{
"delete"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "type"=>"integer", "required"=>true, "format"=>"int32"}],
"tags"=>["dummy"],
"operationId"=>"deleteDummyId",
"responses"=>{"200"=>{"description"=>"dummy route."}, "401"=>{"description"=>"Unauthorized"}}
}}},
"definitions"=>{
"QueryInputElement"=>{"type"=>"object", "properties"=>{"key"=>{"type"=>"string"}, "value"=>{"type"=>"string"}}},
"QueryInput"=>{"type"=>"object", "properties"=>{"elements"=>{"type"=>"array", "items"=>{"$ref"=>"#/definitions/QueryInputElement"}}}},
"Thing"=>{"properties"=>{"id"=>{"type"=>"integer"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}},
"ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer"}, "message"=>{"type"=>"string"}}},
"Something"=>{"type"=>"object", "properties"=>{"id"=>{"type"=>"integer"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}}
}}
"x-amazon-apigateway-integration"=>{"type"=>"aws", "uri"=>"foo_bar_uri", "httpMethod"=>"get"}
}},
"/thing"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[
{"in"=>"query", "name"=>"id", "description"=>"Identity of Something", "required"=>false, "type"=>"integer", "format"=>"int32"},
{"in"=>"query", "name"=>"text", "description"=>"Content of something.", "required"=>false, "type"=>"string"},
{"in"=>"query", "name"=>"links", "description"=>nil, "required"=>false, "type"=>"link"},
{"in"=>"query", "name"=>"others", "description"=>nil, "required"=>false, "type"=>"text"}
],
"responses"=>{"200"=>{"description"=>"This gets Things.", "schema"=>{"$ref"=>"#/definitions/Thing"}}, "401"=>{"description"=>"Unauthorized", "schema"=>{"$ref"=>"#/definitions/ApiError"}}},
"tags"=>["thing"],
"operationId"=>"getThing"
},
"post"=>{
"produces"=>["application/json"],
"consumes"=>["application/json"],
"parameters"=>[
{"in"=>"formData", "name"=>"text", "description"=>"Content of something.", "required"=>true, "type"=>"string"},
{"in"=>"formData", "name"=>"links", "description"=>nil, "required"=>true, "type"=>"array"}
],
"responses"=>{"201"=>{"description"=>"This creates Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}}, "422"=>{"description"=>"Unprocessible Entity"}},
"tags"=>["thing"],
"operationId"=>"postThing"
}},
"/thing/{id}"=>{
"get"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"}],
"responses"=>{"200"=>{"description"=>"getting a single thing", "schema"=>{"$ref"=>"#/definitions/Thing"}}, "401"=>{"description"=>"Unauthorized"}},
"tags"=>["thing"],
"operationId"=>"getThingId"
},
"put"=>{
"produces"=>["application/json"],
"consumes"=>["application/json"],
"parameters"=>[
{"in"=>"path", "name"=>"id", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"},
{"in"=>"formData", "name"=>"text", "description"=>"Content of something.", "required"=>false, "type"=>"string"},
{"in"=>"formData", "name"=>"links", "description"=>nil, "required"=>false, "type"=>"array"}
],
"responses"=>{"200"=>{"description"=>"This updates Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}}},
"tags"=>["thing"],
"operationId"=>"putThingId"
},
"delete"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"}],
"responses"=>{"200"=>{"description"=>"This deletes Thing.", "schema"=>{"$ref"=>"#/definitions/Something"}}},
"tags"=>["thing"],
"operationId"=>"deleteThingId"
}},
"/thing2"=>{
"get"=>{
"produces"=>["application/json"],
"responses"=>{"200"=>{"description"=>"get Horses", "schema"=>{"$ref"=>"#/definitions/Something"}}, "401"=>{"description"=>"HorsesOutError", "schema"=>{"$ref"=>"#/definitions/ApiError"}}},
"tags"=>["thing2"],
"operationId"=>"getThing2"
}},
"/dummy/{id}"=>{
"delete"=>{
"produces"=>["application/json"],
"parameters"=>[{"in"=>"path", "name"=>"id", "description"=>nil, "required"=>true, "type"=>"integer", "format"=>"int32"}],
"responses"=>{"200"=>{"description"=>"dummy route."}, "401"=>{"description"=>"Unauthorized"}},
"tags"=>["dummy"],
"operationId"=>"deleteDummyId"
}}},
"definitions"=>{
"QueryInputElement"=>{"type"=>"object", "properties"=>{"key"=>{"type"=>"string"}, "value"=>{"type"=>"string"}}},
"QueryInput"=>{"type"=>"object", "properties"=>{"elements"=>{"type"=>"array", "items"=>{"$ref"=>"#/definitions/QueryInputElement"}}}},
"Thing"=>{"properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}},
"ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer", "format"=>"int32"}, "message"=>{"type"=>"string"}}},
"Something"=>{"type"=>"object", "properties"=>{"id"=>{"type"=>"integer", "format"=>"int32"}, "text"=>{"type"=>"string"}, "links"=>{"type"=>"link"}, "others"=>{"type"=>"text"}}}
}}
end

let(:http_verbs) { %w[get post put delete]}
Expand Down
Loading

0 comments on commit 168146d

Please sign in to comment.