gitlab-grape-swagger 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.github/dependabot.yml +20 -0
- data/.github/workflows/ci.yml +45 -0
- data/.gitignore +44 -0
- data/.gitlab-ci.yml +19 -0
- data/.rspec +3 -0
- data/.rubocop.yml +136 -0
- data/.rubocop_todo.yml +60 -0
- data/.ruby-gemset +1 -0
- data/CHANGELOG.md +671 -0
- data/CONTRIBUTING.md +126 -0
- data/Dangerfile +3 -0
- data/Gemfile +45 -0
- data/Gemfile.lock +249 -0
- data/LICENSE.txt +20 -0
- data/README.md +1772 -0
- data/RELEASING.md +82 -0
- data/Rakefile +20 -0
- data/UPGRADING.md +201 -0
- data/example/api/endpoints.rb +131 -0
- data/example/api/entities.rb +18 -0
- data/example/config.ru +42 -0
- data/example/example_requests.postman_collection +146 -0
- data/example/splines.png +0 -0
- data/example/swagger-example.png +0 -0
- data/grape-swagger.gemspec +23 -0
- data/lib/grape-swagger/doc_methods/build_model_definition.rb +68 -0
- data/lib/grape-swagger/doc_methods/data_type.rb +110 -0
- data/lib/grape-swagger/doc_methods/extensions.rb +101 -0
- data/lib/grape-swagger/doc_methods/file_params.rb +17 -0
- data/lib/grape-swagger/doc_methods/format_data.rb +53 -0
- data/lib/grape-swagger/doc_methods/headers.rb +20 -0
- data/lib/grape-swagger/doc_methods/move_params.rb +209 -0
- data/lib/grape-swagger/doc_methods/operation_id.rb +32 -0
- data/lib/grape-swagger/doc_methods/optional_object.rb +30 -0
- data/lib/grape-swagger/doc_methods/parse_params.rb +190 -0
- data/lib/grape-swagger/doc_methods/path_string.rb +52 -0
- data/lib/grape-swagger/doc_methods/produces_consumes.rb +15 -0
- data/lib/grape-swagger/doc_methods/status_codes.rb +21 -0
- data/lib/grape-swagger/doc_methods/tag_name_description.rb +34 -0
- data/lib/grape-swagger/doc_methods/version.rb +20 -0
- data/lib/grape-swagger/doc_methods.rb +142 -0
- data/lib/grape-swagger/endpoint/params_parser.rb +76 -0
- data/lib/grape-swagger/endpoint.rb +476 -0
- data/lib/grape-swagger/errors.rb +17 -0
- data/lib/grape-swagger/instance.rb +7 -0
- data/lib/grape-swagger/model_parsers.rb +42 -0
- data/lib/grape-swagger/rake/oapi_tasks.rb +135 -0
- data/lib/grape-swagger/version.rb +5 -0
- data/lib/grape-swagger.rb +174 -0
- data/spec/issues/267_nested_namespaces.rb +55 -0
- data/spec/issues/403_versions_spec.rb +124 -0
- data/spec/issues/427_entity_as_string_spec.rb +39 -0
- data/spec/issues/430_entity_definitions_spec.rb +94 -0
- data/spec/issues/532_allow_custom_format_spec.rb +42 -0
- data/spec/issues/533_specify_status_code_spec.rb +78 -0
- data/spec/issues/537_enum_values_spec.rb +50 -0
- data/spec/issues/539_array_post_body_spec.rb +65 -0
- data/spec/issues/542_array_of_type_in_post_body_spec.rb +46 -0
- data/spec/issues/553_align_array_put_post_params_spec.rb +152 -0
- data/spec/issues/572_array_post_body_spec.rb +51 -0
- data/spec/issues/579_align_put_post_parameters_spec.rb +185 -0
- data/spec/issues/582_file_response_spec.rb +55 -0
- data/spec/issues/587_range_parameter_delimited_by_dash_spec.rb +26 -0
- data/spec/issues/605_root_route_documentation_spec.rb +23 -0
- data/spec/issues/650_params_array_spec.rb +65 -0
- data/spec/issues/677_consumes_produces_add_swagger_documentation_options_spec.rb +100 -0
- data/spec/issues/680_keep_204_error_schemas_spec.rb +55 -0
- data/spec/issues/721_set_default_parameter_location_based_on_consumes_spec.rb +62 -0
- data/spec/issues/751_deeply_nested_objects_spec.rb +190 -0
- data/spec/issues/776_multiple_presents_spec.rb +59 -0
- data/spec/issues/784_extensions_on_params_spec.rb +42 -0
- data/spec/issues/809_utf8_routes_spec.rb +55 -0
- data/spec/issues/832_array_hash_float_decimal_spec.rb +114 -0
- data/spec/issues/847_route_param_options_spec.rb +37 -0
- data/spec/issues/873_wildcard_segments_path_parameters_spec.rb +28 -0
- data/spec/issues/878_optional_path_segments_spec.rb +29 -0
- data/spec/issues/881_handle_file_params_spec.rb +38 -0
- data/spec/issues/883_query_array_parameter_spec.rb +46 -0
- data/spec/issues/884_dont_document_non_schema_examples_spec.rb +49 -0
- data/spec/issues/887_prevent_duplicate_operation_ids_spec.rb +35 -0
- data/spec/lib/data_type_spec.rb +111 -0
- data/spec/lib/endpoint/params_parser_spec.rb +124 -0
- data/spec/lib/endpoint_spec.rb +153 -0
- data/spec/lib/extensions_spec.rb +185 -0
- data/spec/lib/format_data_spec.rb +115 -0
- data/spec/lib/model_parsers_spec.rb +104 -0
- data/spec/lib/move_params_spec.rb +444 -0
- data/spec/lib/oapi_tasks_spec.rb +163 -0
- data/spec/lib/operation_id_spec.rb +55 -0
- data/spec/lib/optional_object_spec.rb +47 -0
- data/spec/lib/parse_params_spec.rb +68 -0
- data/spec/lib/path_string_spec.rb +101 -0
- data/spec/lib/produces_consumes_spec.rb +116 -0
- data/spec/lib/tag_name_description_spec.rb +80 -0
- data/spec/lib/version_spec.rb +28 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/empty_model_parser.rb +23 -0
- data/spec/support/grape_version.rb +13 -0
- data/spec/support/mock_parser.rb +23 -0
- data/spec/support/model_parsers/entity_parser.rb +334 -0
- data/spec/support/model_parsers/mock_parser.rb +346 -0
- data/spec/support/model_parsers/representable_parser.rb +406 -0
- data/spec/support/namespace_tags.rb +93 -0
- data/spec/support/the_paths_definitions.rb +109 -0
- data/spec/swagger_v2/api_documentation_spec.rb +42 -0
- data/spec/swagger_v2/api_swagger_v2_additional_properties_spec.rb +83 -0
- data/spec/swagger_v2/api_swagger_v2_body_definitions_spec.rb +48 -0
- data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +36 -0
- data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +79 -0
- data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +145 -0
- data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +137 -0
- data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +56 -0
- data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +64 -0
- data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +58 -0
- data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +57 -0
- data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +109 -0
- data/spec/swagger_v2/api_swagger_v2_ignore_defaults_spec.rb +48 -0
- data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +153 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +355 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +217 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +247 -0
- data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +80 -0
- data/spec/swagger_v2/api_swagger_v2_response_spec.rb +147 -0
- data/spec/swagger_v2/api_swagger_v2_response_with_examples_spec.rb +135 -0
- data/spec/swagger_v2/api_swagger_v2_response_with_headers_spec.rb +216 -0
- data/spec/swagger_v2/api_swagger_v2_response_with_models_spec.rb +53 -0
- data/spec/swagger_v2/api_swagger_v2_response_with_root_spec.rb +153 -0
- data/spec/swagger_v2/api_swagger_v2_spec.rb +245 -0
- data/spec/swagger_v2/api_swagger_v2_status_codes_spec.rb +93 -0
- data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +90 -0
- data/spec/swagger_v2/boolean_params_spec.rb +38 -0
- data/spec/swagger_v2/default_api_spec.rb +175 -0
- data/spec/swagger_v2/deprecated_field_spec.rb +25 -0
- data/spec/swagger_v2/description_not_initialized_spec.rb +39 -0
- data/spec/swagger_v2/endpoint_versioned_path_spec.rb +130 -0
- data/spec/swagger_v2/errors_spec.rb +77 -0
- data/spec/swagger_v2/float_api_spec.rb +36 -0
- data/spec/swagger_v2/form_params_spec.rb +76 -0
- data/spec/swagger_v2/grape-swagger_spec.rb +17 -0
- data/spec/swagger_v2/guarded_endpoint_spec.rb +162 -0
- data/spec/swagger_v2/hide_api_spec.rb +147 -0
- data/spec/swagger_v2/host_spec.rb +43 -0
- data/spec/swagger_v2/inheritance_and_discriminator_spec.rb +57 -0
- data/spec/swagger_v2/mount_override_api_spec.rb +58 -0
- data/spec/swagger_v2/mounted_target_class_spec.rb +76 -0
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +122 -0
- data/spec/swagger_v2/namespace_tags_spec.rb +78 -0
- data/spec/swagger_v2/namespaced_api_spec.rb +121 -0
- data/spec/swagger_v2/nicknamed_api_spec.rb +25 -0
- data/spec/swagger_v2/operation_id_api_spec.rb +27 -0
- data/spec/swagger_v2/param_multi_type_spec.rb +82 -0
- data/spec/swagger_v2/param_type_spec.rb +95 -0
- data/spec/swagger_v2/param_values_spec.rb +180 -0
- data/spec/swagger_v2/params_array_collection_format_spec.rb +105 -0
- data/spec/swagger_v2/params_array_spec.rb +225 -0
- data/spec/swagger_v2/params_example_spec.rb +38 -0
- data/spec/swagger_v2/params_hash_spec.rb +77 -0
- data/spec/swagger_v2/params_nested_spec.rb +92 -0
- data/spec/swagger_v2/parent_less_namespace_spec.rb +32 -0
- data/spec/swagger_v2/reference_entity_spec.rb +129 -0
- data/spec/swagger_v2/security_requirement_spec.rb +46 -0
- data/spec/swagger_v2/simple_mounted_api_spec.rb +332 -0
- data/spec/version_spec.rb +10 -0
- metadata +225 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'grape'
|
|
4
|
+
|
|
5
|
+
require 'grape-swagger/instance'
|
|
6
|
+
|
|
7
|
+
require 'grape-swagger/version'
|
|
8
|
+
require 'grape-swagger/endpoint'
|
|
9
|
+
require 'grape-swagger/errors'
|
|
10
|
+
|
|
11
|
+
require 'grape-swagger/doc_methods'
|
|
12
|
+
require 'grape-swagger/model_parsers'
|
|
13
|
+
|
|
14
|
+
module GrapeSwagger
|
|
15
|
+
class << self
|
|
16
|
+
def model_parsers
|
|
17
|
+
@model_parsers ||= GrapeSwagger::ModelParsers.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
autoload :Rake, 'grape-swagger/rake/oapi_tasks'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module SwaggerRouting
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def combine_routes(app, doc_klass)
|
|
27
|
+
app.routes.each do |route|
|
|
28
|
+
route_path = route.path
|
|
29
|
+
route_match = route_path.split(/^.*?#{route.prefix}/).last
|
|
30
|
+
next unless route_match
|
|
31
|
+
|
|
32
|
+
# want to match emojis … ;)
|
|
33
|
+
# route_match = route_match
|
|
34
|
+
# .match('\/([\p{Alnum}p{Emoji}\-\_]*?)[\.\/\(]') || route_match.match('\/([\p{Alpha}\p{Emoji}\-\_]*)$')
|
|
35
|
+
route_match = route_match.match('\/([\p{Alnum}\-\_]*?)[\.\/\(]') || route_match.match('\/([\p{Alpha}\-\_]*)$')
|
|
36
|
+
next unless route_match
|
|
37
|
+
|
|
38
|
+
resource = route_match.captures.first
|
|
39
|
+
resource = '/' if resource.empty?
|
|
40
|
+
@target_class.combined_routes[resource] ||= []
|
|
41
|
+
next if doc_klass.hide_documentation_path && route.path.match(/#{doc_klass.mount_path}($|\/|\(\.)/)
|
|
42
|
+
|
|
43
|
+
@target_class.combined_routes[resource].unshift route
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def determine_namespaced_routes(name, parent_route)
|
|
48
|
+
if parent_route.nil?
|
|
49
|
+
@target_class.combined_routes.values.flatten
|
|
50
|
+
else
|
|
51
|
+
parent_route.reject do |route|
|
|
52
|
+
!route_path_start_with?(route, name) || !route_instance_variable_equals?(route, name)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def combine_namespace_routes(namespaces)
|
|
58
|
+
# iterate over each single namespace
|
|
59
|
+
namespaces.each_key do |name, _|
|
|
60
|
+
# get the parent route for the namespace
|
|
61
|
+
parent_route_name = extract_parent_route(name)
|
|
62
|
+
parent_route = @target_class.combined_routes[parent_route_name]
|
|
63
|
+
# fetch all routes that are within the current namespace
|
|
64
|
+
namespace_routes = determine_namespaced_routes(name, parent_route)
|
|
65
|
+
|
|
66
|
+
# default case when not explicitly specified or nested == true
|
|
67
|
+
standalone_namespaces = namespaces.reject do |_, ns|
|
|
68
|
+
!ns.options.key?(:swagger) ||
|
|
69
|
+
!ns.options[:swagger].key?(:nested) ||
|
|
70
|
+
ns.options[:swagger][:nested] != false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
parent_standalone_namespaces = standalone_namespaces.select { |ns_name, _| name.start_with?(ns_name) }
|
|
74
|
+
# add only to the main route
|
|
75
|
+
# if the namespace is not within any other namespace appearing as standalone resource
|
|
76
|
+
# rubocop:disable Style/Next
|
|
77
|
+
if parent_standalone_namespaces.empty?
|
|
78
|
+
# default option, append namespace methods to parent route
|
|
79
|
+
parent_route = @target_class.combined_namespace_routes.key?(parent_route_name)
|
|
80
|
+
@target_class.combined_namespace_routes[parent_route_name] = [] unless parent_route
|
|
81
|
+
@target_class.combined_namespace_routes[parent_route_name].push(*namespace_routes)
|
|
82
|
+
end
|
|
83
|
+
# rubocop:enable Style/Next
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def extract_parent_route(name)
|
|
88
|
+
route_name = name.match(%r{^/?([^/]*).*$})[1]
|
|
89
|
+
return route_name unless route_name.include? ':'
|
|
90
|
+
|
|
91
|
+
matches = name.match(/\/\p{Alpha}+/)
|
|
92
|
+
matches.nil? ? route_name : matches[0].delete('/')
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def route_instance_variable(route)
|
|
96
|
+
route.instance_variable_get(:@options)[:namespace]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def route_instance_variable_equals?(route, name)
|
|
100
|
+
route_instance_variable(route) == "/#{name}" ||
|
|
101
|
+
route_instance_variable(route) == "/:version/#{name}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def route_path_start_with?(route, name)
|
|
105
|
+
route_prefix = route.prefix ? "/#{route.prefix}/#{name}" : "/#{name}"
|
|
106
|
+
route_versioned_prefix = route.prefix ? "/#{route.prefix}/:version/#{name}" : "/:version/#{name}"
|
|
107
|
+
|
|
108
|
+
route.path.start_with?(route_prefix, route_versioned_prefix)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
module SwaggerDocumentationAdder
|
|
113
|
+
attr_accessor :combined_namespaces, :combined_namespace_identifiers, :combined_routes, :combined_namespace_routes
|
|
114
|
+
|
|
115
|
+
include SwaggerRouting
|
|
116
|
+
|
|
117
|
+
def add_swagger_documentation(options = {})
|
|
118
|
+
documentation_class = create_documentation_class
|
|
119
|
+
|
|
120
|
+
version_for(options)
|
|
121
|
+
options = { target_class: self }.merge(options)
|
|
122
|
+
@target_class = options[:target_class]
|
|
123
|
+
auth_wrapper = options[:endpoint_auth_wrapper] || Class.new
|
|
124
|
+
|
|
125
|
+
use auth_wrapper if auth_wrapper.method_defined?(:before) && !middleware.flatten.include?(auth_wrapper)
|
|
126
|
+
|
|
127
|
+
documentation_class.setup(options)
|
|
128
|
+
mount(documentation_class)
|
|
129
|
+
|
|
130
|
+
@target_class.combined_routes = {}
|
|
131
|
+
combine_routes(@target_class, documentation_class)
|
|
132
|
+
|
|
133
|
+
@target_class.combined_namespaces = {}
|
|
134
|
+
combine_namespaces(@target_class)
|
|
135
|
+
|
|
136
|
+
@target_class.combined_namespace_routes = {}
|
|
137
|
+
@target_class.combined_namespace_identifiers = {}
|
|
138
|
+
combine_namespace_routes(@target_class.combined_namespaces)
|
|
139
|
+
|
|
140
|
+
exclusive_route_keys = @target_class.combined_routes.keys - @target_class.combined_namespaces.keys
|
|
141
|
+
exclusive_route_keys.each do |key|
|
|
142
|
+
@target_class.combined_namespace_routes[key] = @target_class.combined_routes[key]
|
|
143
|
+
end
|
|
144
|
+
documentation_class
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def version_for(options)
|
|
150
|
+
options[:version] = version if version
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def combine_namespaces(app)
|
|
154
|
+
app.endpoints.each do |endpoint|
|
|
155
|
+
ns = endpoint.namespace_stackable(:namespace).last
|
|
156
|
+
|
|
157
|
+
# use the full namespace here (not the latest level only)
|
|
158
|
+
# and strip leading slash
|
|
159
|
+
mount_path = (endpoint.namespace_stackable(:mount_path) || []).join('/')
|
|
160
|
+
full_namespace = (mount_path + endpoint.namespace).sub(/\/{2,}/, '/').sub(/^\//, '')
|
|
161
|
+
@target_class.combined_namespaces[full_namespace] = ns if ns
|
|
162
|
+
|
|
163
|
+
combine_namespaces(endpoint.options[:app]) if endpoint.options[:app]
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def create_documentation_class
|
|
168
|
+
Class.new(GrapeInstance) do
|
|
169
|
+
extend GrapeSwagger::DocMethods
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
GrapeInstance.extend(SwaggerDocumentationAdder)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'nested namespaces' do
|
|
6
|
+
let(:app) do
|
|
7
|
+
Class.new(Grape::API) do
|
|
8
|
+
route_param :root do
|
|
9
|
+
resources :apps do
|
|
10
|
+
route_param :app_id do
|
|
11
|
+
resource :build do
|
|
12
|
+
desc 'Builds an application'
|
|
13
|
+
post do
|
|
14
|
+
{ name: 'Test' }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
add_swagger_documentation version: 'v1'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe 'combined_namespace_routes' do
|
|
26
|
+
it 'parses root namespace properly' do
|
|
27
|
+
expect(app.combined_namespace_routes.keys).to include('apps')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#extract_parent_route' do
|
|
32
|
+
it 'extracts parent for non-namespaced path properly' do
|
|
33
|
+
expect(app.send(:extract_parent_route, '/apps/:app_id/build')).to eq('apps')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'extracts parent for namespaced path properly' do
|
|
37
|
+
expect(app.send(:extract_parent_route, '/:root/apps/:app_id/build')).to eq('apps')
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe 'retrieves swagger-documentation on /swagger_doc' do
|
|
42
|
+
let(:route_name) { '{root}/apps/{app_id}/build' }
|
|
43
|
+
|
|
44
|
+
subject do
|
|
45
|
+
get '/swagger_doc.json'
|
|
46
|
+
JSON.parse(last_response.body)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'paths' do
|
|
50
|
+
specify do
|
|
51
|
+
expect(subject['paths'].keys).to include "/#{route_name}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'describing versions' do
|
|
6
|
+
describe 'nothings given' do
|
|
7
|
+
def app
|
|
8
|
+
Class.new(Grape::API) do
|
|
9
|
+
desc 'no versions given'
|
|
10
|
+
get '/nothings' do
|
|
11
|
+
{ message: 'hello world …' }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_swagger_documentation format: :json
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
subject do
|
|
19
|
+
get '/swagger_doc'
|
|
20
|
+
JSON.parse(last_response.body)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
specify do
|
|
24
|
+
expect(subject['info']['version']).to eql '0.0.1'
|
|
25
|
+
expect(subject['paths'].keys.first).to eql '/nothings'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe 'API version given' do
|
|
30
|
+
def app
|
|
31
|
+
Class.new(Grape::API) do
|
|
32
|
+
version 'v2', using: :path
|
|
33
|
+
desc 'api versions given'
|
|
34
|
+
get '/api_version' do
|
|
35
|
+
{ message: 'hello world …' }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
add_swagger_documentation format: :json
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
subject do
|
|
43
|
+
get '/v2/swagger_doc'
|
|
44
|
+
JSON.parse(last_response.body)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
specify do
|
|
48
|
+
expect(subject['info']['version']).to eql '0.0.1'
|
|
49
|
+
expect(subject['paths'].keys.first).to eql '/v2/api_version'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe 'DOC version given' do
|
|
54
|
+
def app
|
|
55
|
+
Class.new(Grape::API) do
|
|
56
|
+
desc 'doc versions given'
|
|
57
|
+
get '/doc_version' do
|
|
58
|
+
{ message: 'hello world …' }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
add_swagger_documentation doc_version: '0.1'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
subject do
|
|
66
|
+
get '/swagger_doc'
|
|
67
|
+
JSON.parse(last_response.body)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
specify do
|
|
71
|
+
expect(subject['info']['version']).to eql '0.1'
|
|
72
|
+
expect(subject['paths'].keys.first).to eql '/doc_version'
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe 'both versions given' do
|
|
77
|
+
def app
|
|
78
|
+
Class.new(Grape::API) do
|
|
79
|
+
version :v3, using: :path
|
|
80
|
+
desc 'both versions given'
|
|
81
|
+
get '/both_versions' do
|
|
82
|
+
{ message: 'hello world …' }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
add_swagger_documentation doc_version: '0.2'
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
subject do
|
|
90
|
+
get '/v3/swagger_doc'
|
|
91
|
+
JSON.parse(last_response.body)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
specify do
|
|
95
|
+
expect(subject['info']['version']).to eql '0.2'
|
|
96
|
+
expect(subject['paths'].keys.first).to eql '/v3/both_versions'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe 'try to override grape given version' do
|
|
101
|
+
def app
|
|
102
|
+
Class.new(Grape::API) do
|
|
103
|
+
version :v4, using: :path
|
|
104
|
+
desc 'overriding grape given version?'
|
|
105
|
+
get '/grape_version' do
|
|
106
|
+
{ message: 'hello world …' }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
add_swagger_documentation doc_version: '0.0.3',
|
|
110
|
+
version: 'v5'
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
subject do
|
|
115
|
+
get '/v4/swagger_doc'
|
|
116
|
+
JSON.parse(last_response.body)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
specify do
|
|
120
|
+
expect(subject['info']['version']).to eql '0.0.3'
|
|
121
|
+
expect(subject['paths'].keys.first).to eql '/v4/grape_version'
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe '#427 nested entity given as string' do
|
|
6
|
+
let(:app) do
|
|
7
|
+
Class.new(Grape::API) do
|
|
8
|
+
namespace :issue_427 do
|
|
9
|
+
module Permission
|
|
10
|
+
class WithoutRole < Grape::Entity
|
|
11
|
+
expose :id
|
|
12
|
+
expose :description
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class RoleEntity < Grape::Entity
|
|
17
|
+
expose :id
|
|
18
|
+
expose :description
|
|
19
|
+
expose :role
|
|
20
|
+
expose :permissions, using: 'Permission::WithoutRole'
|
|
21
|
+
end
|
|
22
|
+
desc 'Get a list of roles',
|
|
23
|
+
success: RoleEntity
|
|
24
|
+
get '/' do
|
|
25
|
+
present [], with: RoleEntity
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
add_swagger_documentation format: :json
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
subject do
|
|
34
|
+
get '/swagger_doc'
|
|
35
|
+
JSON.parse(last_response.body)['definitions']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
specify { expect(subject.keys).to include 'RoleEntity', 'Permission_WithoutRole' }
|
|
39
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'definition names' do
|
|
6
|
+
before :all do
|
|
7
|
+
module TestDefinition
|
|
8
|
+
module DummyEntities
|
|
9
|
+
module WithVeryLongName
|
|
10
|
+
module AnotherGroupingModule
|
|
11
|
+
class Class1
|
|
12
|
+
class Entity < Grape::Entity
|
|
13
|
+
expose :first_thing
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Class2
|
|
18
|
+
class Entities < Grape::Entity
|
|
19
|
+
expose :second_thing
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Class3
|
|
24
|
+
class Entity < Grape::Entity
|
|
25
|
+
expose :third_thing
|
|
26
|
+
|
|
27
|
+
def self.entity_name
|
|
28
|
+
'FooKlass'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Class4
|
|
34
|
+
class FourthEntity < Grape::Entity
|
|
35
|
+
expose :fourth_thing
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Class5
|
|
40
|
+
class FithEntity < Class4::FourthEntity
|
|
41
|
+
expose :fith_thing
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Class6
|
|
46
|
+
class SixthEntity < Grape::Entity
|
|
47
|
+
expose :sixth_thing
|
|
48
|
+
|
|
49
|
+
def self.entity_name
|
|
50
|
+
'BarKlass'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class Class7
|
|
56
|
+
class SeventhEntity < Class6::SixthEntity
|
|
57
|
+
expose :seventh_thing
|
|
58
|
+
|
|
59
|
+
private_class_method :entity_name
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class NameApi < Grape::API
|
|
67
|
+
add_swagger_documentation models: [
|
|
68
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class1::Entity,
|
|
69
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class2::Entities,
|
|
70
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class3::Entity,
|
|
71
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class4::FourthEntity,
|
|
72
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class5::FithEntity,
|
|
73
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class6::SixthEntity,
|
|
74
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class7::SeventhEntity
|
|
75
|
+
]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
let(:app) { TestDefinition::NameApi }
|
|
81
|
+
|
|
82
|
+
subject do
|
|
83
|
+
get '/swagger_doc'
|
|
84
|
+
JSON.parse(last_response.body)['definitions']
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class1' }
|
|
88
|
+
specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class2' }
|
|
89
|
+
specify { expect(subject).to include 'FooKlass' }
|
|
90
|
+
specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class4_FourthEntity' }
|
|
91
|
+
specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class5_FithEntity' }
|
|
92
|
+
specify { expect(subject).to include 'BarKlass' }
|
|
93
|
+
specify { expect(subject).to include 'TestDefinition_DummyEntities_WithVeryLongName_AnotherGroupingModule_Class7_SeventhEntity' }
|
|
94
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe '#532 allow custom format' do
|
|
6
|
+
let(:app) do
|
|
7
|
+
Class.new(Grape::API) do
|
|
8
|
+
namespace :issue_532 do
|
|
9
|
+
desc 'issue_532' do
|
|
10
|
+
consumes ['application/x-www-form-urlencoded']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
params do
|
|
14
|
+
requires :logs, type: String, documentation: { format: 'log' }
|
|
15
|
+
optional :phone_number, type: Integer, documentation: { format: 'phone_number' }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
post do
|
|
19
|
+
present params
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
add_swagger_documentation format: :json
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subject do
|
|
28
|
+
get '/swagger_doc'
|
|
29
|
+
JSON.parse(last_response.body)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
let(:parameters) { subject['paths']['/issue_532']['post']['parameters'] }
|
|
33
|
+
|
|
34
|
+
specify do
|
|
35
|
+
expect(parameters).to eql(
|
|
36
|
+
[
|
|
37
|
+
{ 'in' => 'formData', 'name' => 'logs', 'type' => 'string', 'format' => 'log', 'required' => true },
|
|
38
|
+
{ 'in' => 'formData', 'name' => 'phone_number', 'type' => 'integer', 'format' => 'phone_number', 'required' => false }
|
|
39
|
+
]
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe '#533 specify status codes' do
|
|
6
|
+
include_context "#{MODEL_PARSER} swagger example"
|
|
7
|
+
|
|
8
|
+
let(:app) do
|
|
9
|
+
Class.new(Grape::API) do
|
|
10
|
+
namespace :issue_533 do
|
|
11
|
+
desc 'Get a list of stuff',
|
|
12
|
+
success: { code: 202, model: Entities::UseResponse, message: 'a changed status code' }
|
|
13
|
+
get do
|
|
14
|
+
status 202
|
|
15
|
+
{ foo: 'that is the response' }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'Post some stuff',
|
|
19
|
+
success: { code: 202, model: Entities::UseResponse, message: 'a changed status code' }
|
|
20
|
+
post do
|
|
21
|
+
status 202
|
|
22
|
+
{ foo: 'that is the response' }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc 'Post some stuff',
|
|
26
|
+
success: { code: 204, message: 'a changed status code' }
|
|
27
|
+
patch do
|
|
28
|
+
status 204
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
desc 'Delete some stuff',
|
|
32
|
+
success: { code: 203 }
|
|
33
|
+
delete do
|
|
34
|
+
status 203
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
add_swagger_documentation format: :json
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
subject do
|
|
43
|
+
get '/swagger_doc'
|
|
44
|
+
JSON.parse(last_response.body)['paths']['/issue_533']
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
let(:get_response) { get '/issue_533' }
|
|
48
|
+
specify { expect(get_response.status).to eql 202 }
|
|
49
|
+
let(:get_response_documentation) { subject['get']['responses'] }
|
|
50
|
+
specify do
|
|
51
|
+
expect(get_response_documentation.keys.first).to eql '202'
|
|
52
|
+
expect(get_response_documentation['202']).to include 'schema'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
let(:post_response) { post '/issue_533' }
|
|
56
|
+
specify { expect(post_response.status).to eql 202 }
|
|
57
|
+
let(:post_response_documentation) { subject['post']['responses'] }
|
|
58
|
+
specify do
|
|
59
|
+
expect(post_response_documentation.keys.first).to eql '202'
|
|
60
|
+
expect(post_response_documentation['202']).to include 'schema'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
let(:patch_response) { patch '/issue_533' }
|
|
64
|
+
specify { expect(patch_response.status).to eql 204 }
|
|
65
|
+
let(:patch_response_documentation) { subject['patch']['responses'] }
|
|
66
|
+
specify do
|
|
67
|
+
expect(patch_response_documentation.keys.first).to eql '204'
|
|
68
|
+
expect(patch_response_documentation['204']).not_to include 'schema'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
let(:delete_response) { delete '/issue_533' }
|
|
72
|
+
specify { expect(delete_response.status).to eql 203 }
|
|
73
|
+
let(:delete_response_documentation) { subject['delete']['responses'] }
|
|
74
|
+
specify do
|
|
75
|
+
expect(delete_response_documentation.keys.first).to eql '203'
|
|
76
|
+
expect(delete_response_documentation['203']).not_to include 'schema'
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe '#537 enum values spec' do
|
|
6
|
+
let(:app) do
|
|
7
|
+
Class.new(Grape::API) do
|
|
8
|
+
namespace :issue_537 do
|
|
9
|
+
class Spec < Grape::Entity
|
|
10
|
+
expose :enum_property, documentation: { values: %i[foo bar] }
|
|
11
|
+
expose :enum_property_default, documentation: { values: %w[a b c], default: 'c' }
|
|
12
|
+
expose :own_format, documentation: { format: 'log' }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc 'create account',
|
|
16
|
+
success: Spec
|
|
17
|
+
get do
|
|
18
|
+
{ message: 'hi' }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
add_swagger_documentation format: :json
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
subject do
|
|
27
|
+
get '/swagger_doc'
|
|
28
|
+
JSON.parse(last_response.body)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
let(:property) { subject['definitions']['Spec']['properties']['enum_property'] }
|
|
32
|
+
specify do
|
|
33
|
+
expect(property).to include 'enum'
|
|
34
|
+
expect(property['enum']).to eql %w[foo bar]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
let(:property_default) { subject['definitions']['Spec']['properties']['enum_property_default'] }
|
|
38
|
+
specify do
|
|
39
|
+
expect(property_default).to include 'enum'
|
|
40
|
+
expect(property_default['enum']).to eql %w[a b c]
|
|
41
|
+
expect(property_default).to include 'default'
|
|
42
|
+
expect(property_default['default']).to eql 'c'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
let(:own_format) { subject['definitions']['Spec']['properties']['own_format'] }
|
|
46
|
+
specify do
|
|
47
|
+
expect(own_format).to include 'format'
|
|
48
|
+
expect(own_format['format']).to eql 'log'
|
|
49
|
+
end
|
|
50
|
+
end
|