praxis 2.0.pre.17 → 2.0.pre.21
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 +4 -4
- data/.rubocop.yml +54 -0
- data/.simplecov +3 -1
- data/.travis.yml +2 -1
- data/CHANGELOG.md +19 -0
- data/CONTRIBUTING.md +2 -79
- data/Gemfile +5 -1
- data/Guardfile +6 -4
- data/LICENSE +0 -2
- data/MAINTAINERS.md +1 -0
- data/README.md +15 -22
- data/Rakefile +4 -2
- data/bin/praxis +55 -58
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +5 -6
- data/lib/praxis/action_definition.rb +65 -95
- data/lib/praxis/api_definition.rb +21 -29
- data/lib/praxis/api_general_info.rb +55 -66
- data/lib/praxis/application.rb +15 -32
- data/lib/praxis/blueprint.rb +80 -73
- data/lib/praxis/bootloader.rb +24 -33
- data/lib/praxis/bootloader_stages/environment.rb +5 -10
- data/lib/praxis/bootloader_stages/file_loader.rb +3 -6
- data/lib/praxis/bootloader_stages/plugin_config_load.rb +4 -6
- data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +2 -2
- data/lib/praxis/bootloader_stages/plugin_loader.rb +3 -7
- data/lib/praxis/bootloader_stages/plugin_setup.rb +3 -3
- data/lib/praxis/bootloader_stages/routing.rb +5 -8
- data/lib/praxis/bootloader_stages/subgroup_loader.rb +2 -10
- data/lib/praxis/bootloader_stages/warn_unloaded_files.rb +15 -19
- data/lib/praxis/callbacks.rb +12 -11
- data/lib/praxis/collection.rb +11 -14
- data/lib/praxis/config.rb +17 -28
- data/lib/praxis/config_hash.rb +2 -1
- data/lib/praxis/controller.rb +7 -6
- data/lib/praxis/dispatcher.rb +34 -42
- data/lib/praxis/docs/open_api/info_object.rb +11 -8
- data/lib/praxis/docs/open_api/media_type_object.rb +18 -17
- data/lib/praxis/docs/open_api/operation_object.rb +7 -4
- data/lib/praxis/docs/open_api/parameter_object.rb +17 -14
- data/lib/praxis/docs/open_api/paths_object.rb +11 -9
- data/lib/praxis/docs/open_api/request_body_object.rb +14 -13
- data/lib/praxis/docs/open_api/response_object.rb +24 -18
- data/lib/praxis/docs/open_api/responses_object.rb +3 -1
- data/lib/praxis/docs/open_api/schema_object.rb +61 -29
- data/lib/praxis/docs/open_api/server_object.rb +5 -2
- data/lib/praxis/docs/open_api/tag_object.rb +9 -6
- data/lib/praxis/docs/open_api_generator.rb +114 -150
- data/lib/praxis/endpoint_definition.rb +60 -77
- data/lib/praxis/error_handler.rb +2 -2
- data/lib/praxis/exception.rb +2 -0
- data/lib/praxis/exceptions/config.rb +3 -1
- data/lib/praxis/exceptions/config_load.rb +2 -0
- data/lib/praxis/exceptions/config_validation.rb +3 -1
- data/lib/praxis/exceptions/invalid_configuration.rb +3 -1
- data/lib/praxis/exceptions/invalid_response.rb +3 -1
- data/lib/praxis/exceptions/invalid_trait.rb +3 -1
- data/lib/praxis/exceptions/stage_not_found.rb +3 -1
- data/lib/praxis/exceptions/validation.rb +4 -3
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +163 -149
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/5x.rb +18 -13
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_0.rb +13 -9
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_1_plus.rb +14 -11
- data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +12 -9
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +8 -5
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +89 -65
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +68 -62
- data/lib/praxis/extensions/attribute_filtering.rb +3 -1
- data/lib/praxis/extensions/field_expansion.rb +6 -4
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +10 -8
- data/lib/praxis/extensions/field_selection/field_selector.rb +91 -92
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +12 -12
- data/lib/praxis/extensions/field_selection.rb +3 -1
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +6 -4
- data/lib/praxis/extensions/pagination/header_generator.rb +16 -11
- data/lib/praxis/extensions/pagination/ordering_params.rb +29 -28
- data/lib/praxis/extensions/pagination/pagination_handler.rb +44 -42
- data/lib/praxis/extensions/pagination/pagination_params.rb +29 -48
- data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +8 -7
- data/lib/praxis/extensions/pagination.rb +10 -15
- data/lib/praxis/extensions/rails_compat/request_methods.rb +3 -4
- data/lib/praxis/extensions/rails_compat.rb +2 -0
- data/lib/praxis/extensions/rendering.rb +12 -12
- data/lib/praxis/field_expander.rb +8 -9
- data/lib/praxis/file_group.rb +8 -12
- data/lib/praxis/finalizable.rb +1 -0
- data/lib/praxis/handlers/json.rb +5 -2
- data/lib/praxis/handlers/plain.rb +2 -1
- data/lib/praxis/handlers/www_form.rb +6 -3
- data/lib/praxis/handlers/{xml-sample.rb → xml_sample.rb} +26 -22
- data/lib/praxis/mapper/active_model_compat.rb +13 -10
- data/lib/praxis/mapper/resource.rb +196 -181
- data/lib/praxis/mapper/selector_generator.rb +106 -112
- data/lib/praxis/mapper/sequel_compat.rb +70 -67
- data/lib/praxis/media_type.rb +2 -2
- data/lib/praxis/media_type_identifier.rb +26 -22
- data/lib/praxis/middleware_app.rb +18 -15
- data/lib/praxis/multipart/parser.rb +46 -51
- data/lib/praxis/multipart/part.rb +78 -110
- data/lib/praxis/notifications.rb +2 -4
- data/lib/praxis/plugin.rb +11 -18
- data/lib/praxis/plugin_concern.rb +12 -15
- data/lib/praxis/plugins/mapper_plugin.rb +15 -13
- data/lib/praxis/plugins/pagination_plugin.rb +8 -6
- data/lib/praxis/plugins/rails_plugin.rb +33 -28
- data/lib/praxis/renderer.rb +11 -15
- data/lib/praxis/request.rb +48 -44
- data/lib/praxis/request_stages/action.rb +4 -6
- data/lib/praxis/request_stages/load_request.rb +2 -4
- data/lib/praxis/request_stages/request_stage.rb +19 -23
- data/lib/praxis/request_stages/response.rb +4 -6
- data/lib/praxis/request_stages/validate.rb +3 -5
- data/lib/praxis/request_stages/validate_params_and_headers.rb +15 -22
- data/lib/praxis/request_stages/validate_payload.rb +25 -28
- data/lib/praxis/request_superclassing.rb +3 -3
- data/lib/praxis/resource_definition.rb +1 -0
- data/lib/praxis/response.rb +24 -26
- data/lib/praxis/response_definition.rb +77 -122
- data/lib/praxis/response_template.rb +11 -15
- data/lib/praxis/responses/http.rb +23 -44
- data/lib/praxis/responses/internal_server_error.rb +18 -21
- data/lib/praxis/responses/multipart_ok.rb +4 -9
- data/lib/praxis/responses/validation_error.rb +8 -15
- data/lib/praxis/route.rb +8 -10
- data/lib/praxis/router/rack.rb +13 -7
- data/lib/praxis/router/simple.rb +10 -5
- data/lib/praxis/router.rb +27 -34
- data/lib/praxis/routing_config.rb +52 -29
- data/lib/praxis/simple_media_type.rb +5 -8
- data/lib/praxis/stage.rb +17 -25
- data/lib/praxis/tasks/api_docs.rb +17 -16
- data/lib/praxis/tasks/console.rb +3 -1
- data/lib/praxis/tasks/environment.rb +2 -0
- data/lib/praxis/tasks/routes.rb +26 -24
- data/lib/praxis/tasks.rb +3 -1
- data/lib/praxis/trait.rb +37 -46
- data/lib/praxis/types/fuzzy_hash.rb +13 -14
- data/lib/praxis/types/media_type_common.rb +11 -10
- data/lib/praxis/types/multipart_array/part_definition.rb +14 -17
- data/lib/praxis/types/multipart_array.rb +100 -115
- data/lib/praxis/validation_handler.rb +5 -3
- data/lib/praxis/version.rb +3 -1
- data/lib/praxis.rb +4 -5
- data/praxis.gemspec +22 -21
- data/spec/functional_spec.rb +44 -56
- data/spec/praxis/action_definition_spec.rb +39 -48
- data/spec/praxis/api_definition_spec.rb +45 -47
- data/spec/praxis/api_general_info_spec.rb +28 -29
- data/spec/praxis/application_spec.rb +18 -14
- data/spec/praxis/blueprint_spec.rb +33 -34
- data/spec/praxis/bootloader_spec.rb +32 -30
- data/spec/praxis/callbacks_spec.rb +37 -37
- data/spec/praxis/collection_spec.rb +18 -25
- data/spec/praxis/config_hash_spec.rb +5 -4
- data/spec/praxis/config_spec.rb +27 -26
- data/spec/praxis/controller_spec.rb +8 -9
- data/spec/praxis/endpoint_definition_spec.rb +25 -32
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +171 -114
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +22 -21
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +112 -60
- data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +37 -38
- data/spec/praxis/extensions/field_expansion_spec.rb +8 -10
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +14 -13
- data/spec/praxis/extensions/field_selection/field_selector_spec.rb +9 -16
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +50 -49
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +32 -31
- data/spec/praxis/extensions/rendering_spec.rb +9 -9
- data/spec/praxis/extensions/support/spec_resources_active_model.rb +32 -49
- data/spec/praxis/extensions/support/spec_resources_sequel.rb +48 -48
- data/spec/praxis/field_expander_spec.rb +6 -5
- data/spec/praxis/file_group_spec.rb +3 -1
- data/spec/praxis/handlers/json_spec.rb +6 -5
- data/spec/praxis/mapper/resource_spec.rb +39 -29
- data/spec/praxis/mapper/selector_generator_spec.rb +80 -46
- data/spec/praxis/media_type_identifier_spec.rb +13 -10
- data/spec/praxis/media_type_spec.rb +12 -12
- data/spec/praxis/middleware_app_spec.rb +23 -22
- data/spec/praxis/multipart/parser_spec.rb +7 -9
- data/spec/praxis/notifications_spec.rb +4 -4
- data/spec/praxis/plugin_concern_spec.rb +5 -6
- data/spec/praxis/renderer_spec.rb +10 -9
- data/spec/praxis/request_spec.rb +38 -41
- data/spec/praxis/request_stages/action_spec.rb +14 -15
- data/spec/praxis/request_stages/request_stage_spec.rb +30 -41
- data/spec/praxis/request_stages/validate_spec.rb +3 -1
- data/spec/praxis/response_definition_spec.rb +79 -92
- data/spec/praxis/response_spec.rb +35 -40
- data/spec/praxis/responses/internal_server_error_spec.rb +6 -9
- data/spec/praxis/responses/validation_error_spec.rb +17 -18
- data/spec/praxis/route_spec.rb +4 -7
- data/spec/praxis/router_spec.rb +69 -79
- data/spec/praxis/routing_config_spec.rb +15 -14
- data/spec/praxis/stage_spec.rb +56 -53
- data/spec/praxis/trait_spec.rb +17 -17
- data/spec/praxis/types/fuzzy_hash_spec.rb +11 -9
- data/spec/praxis/types/multipart_array/part_definition_spec.rb +3 -2
- data/spec/praxis/types/multipart_array_spec.rb +33 -48
- data/spec/spec_app/app/concerns/authenticated.rb +5 -5
- data/spec/spec_app/app/concerns/basic_api.rb +3 -1
- data/spec/spec_app/app/concerns/log_wrapper.rb +5 -3
- data/spec/spec_app/app/controllers/base_class.rb +6 -5
- data/spec/spec_app/app/controllers/instances.rb +31 -34
- data/spec/spec_app/app/controllers/volumes.rb +6 -6
- data/spec/spec_app/app/responses/multipart.rb +1 -2
- data/spec/spec_app/app/responses/other_response.rb +2 -2
- data/spec/spec_app/config/environment.rb +19 -6
- data/spec/spec_app/config.ru +4 -3
- data/spec/spec_app/design/api.rb +13 -15
- data/spec/spec_app/design/media_types/instance.rb +6 -6
- data/spec/spec_app/design/media_types/volume.rb +2 -1
- data/spec/spec_app/design/media_types/volume_snapshot.rb +2 -1
- data/spec/spec_app/design/resources/instances.rb +11 -17
- data/spec/spec_app/design/resources/volume_snapshots.rb +4 -5
- data/spec/spec_app/design/resources/volumes.rb +4 -5
- data/spec/spec_helper.rb +11 -13
- data/spec/support/be_deep_equal_matcher.rb +5 -0
- data/spec/support/spec_authorization_plugin.rb +7 -12
- data/spec/support/spec_blueprints.rb +5 -4
- data/spec/support/spec_complex_authentication_plugin.rb +17 -34
- data/spec/support/spec_endpoint_definitions.rb +2 -3
- data/spec/support/spec_media_types.rb +28 -35
- data/spec/support/spec_resources.rb +22 -16
- data/spec/support/spec_simple_authentication_plugin.rb +5 -9
- data/tasks/loader.thor +4 -2
- data/tasks/thor/app.rb +7 -5
- data/tasks/thor/example.rb +23 -22
- data/tasks/thor/model.rb +7 -7
- data/tasks/thor/scaffold.rb +23 -23
- data/tasks/thor/templates/generator/example_app/app/v1/resources/user.rb +0 -8
- data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +1 -2
- metadata +72 -84
- data/MAINTAINERS +0 -2
- data/TODO.md +0 -25
- data/spec/praxis/api_resource_spec.rb +0 -0
- data/spec/praxis/dispatcher_spec.rb +0 -0
- data/spec/spec_app/app/responses/bulk_response.rb +0 -0
|
@@ -1,56 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require_relative 'open_api/
|
|
4
|
-
require_relative 'open_api/
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'open_api/info_object'
|
|
4
|
+
require_relative 'open_api/server_object'
|
|
5
|
+
require_relative 'open_api/paths_object'
|
|
6
|
+
require_relative 'open_api/tag_object'
|
|
5
7
|
|
|
6
8
|
module Praxis
|
|
7
9
|
module Docs
|
|
8
|
-
|
|
9
10
|
class OpenApiGenerator
|
|
10
11
|
require 'active_support/core_ext/enumerable' # For index_by
|
|
12
|
+
include Singleton
|
|
11
13
|
|
|
12
|
-
API_DOCS_DIRNAME = 'docs/openapi'
|
|
14
|
+
API_DOCS_DIRNAME = 'docs/openapi'
|
|
13
15
|
EXCLUDED_TYPES_FROM_OUTPUT = Set.new([
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
attr_reader :resources_by_version, :
|
|
16
|
+
Attributor::Boolean,
|
|
17
|
+
Attributor::CSV,
|
|
18
|
+
Attributor::DateTime,
|
|
19
|
+
Attributor::Date,
|
|
20
|
+
Attributor::Float,
|
|
21
|
+
Attributor::Hash,
|
|
22
|
+
Attributor::Ids,
|
|
23
|
+
Attributor::Integer,
|
|
24
|
+
Attributor::Object,
|
|
25
|
+
Attributor::String,
|
|
26
|
+
Attributor::Symbol,
|
|
27
|
+
Attributor::URI
|
|
28
|
+
]).freeze
|
|
29
|
+
|
|
30
|
+
attr_reader :resources_by_version, :infos_by_version, :doc_root_dir
|
|
29
31
|
|
|
30
32
|
# substitutes ":params_like_so" for {params_like_so}
|
|
31
|
-
def self.templatize_url(
|
|
33
|
+
def self.templatize_url(string)
|
|
32
34
|
Mustermann.new(string).to_templates.first
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def save!
|
|
38
|
+
raise 'You need to configure the root directory before saving (configure_root(<dir>))' unless @root
|
|
39
|
+
|
|
36
40
|
initialize_directories
|
|
37
41
|
# Restrict the versions listed in the index file to the ones for which we have at least 1 resource
|
|
38
|
-
write_index_file(
|
|
39
|
-
resources_by_version.
|
|
42
|
+
write_index_file(for_versions: resources_by_version.keys)
|
|
43
|
+
resources_by_version.each_key do |version|
|
|
44
|
+
@seen_components_for_current_version = Set.new
|
|
40
45
|
write_version_file(version)
|
|
41
46
|
end
|
|
42
47
|
end
|
|
43
48
|
|
|
44
|
-
def initialize
|
|
49
|
+
def initialize
|
|
45
50
|
require 'yaml'
|
|
46
|
-
|
|
47
|
-
@resources_by_version =
|
|
51
|
+
|
|
52
|
+
@resources_by_version = Hash.new do |h, k|
|
|
48
53
|
h[k] = Set.new
|
|
49
54
|
end
|
|
50
|
-
|
|
55
|
+
# List of types that we have seen/marked as necessary to list in the components/schemas section
|
|
56
|
+
# These should contain any mediatype define in the versioned controllers plus any type
|
|
57
|
+
# for which we've explicitly rendered a $ref schema
|
|
58
|
+
@seen_components_for_current_version = Set.new
|
|
51
59
|
@infos = ApiDefinition.instance.infos
|
|
52
60
|
collect_resources
|
|
53
|
-
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def configure_root(root)
|
|
64
|
+
@root = root
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def register_seen_component(type)
|
|
68
|
+
@seen_components_for_current_version.add(type)
|
|
54
69
|
end
|
|
55
70
|
|
|
56
71
|
private
|
|
@@ -60,6 +75,7 @@ module Praxis
|
|
|
60
75
|
Praxis::Application.instance.endpoint_definitions.map do |resource|
|
|
61
76
|
# skip resources with doc_visibility of :none
|
|
62
77
|
next if resource.metadata[:doc_visibility] == :none
|
|
78
|
+
|
|
63
79
|
version = resource.version
|
|
64
80
|
# TODO: it seems that we shouldn't hardcode n/a in Praxis
|
|
65
81
|
# version = "unversioned" if version == "n/a"
|
|
@@ -67,88 +83,41 @@ module Praxis
|
|
|
67
83
|
end
|
|
68
84
|
end
|
|
69
85
|
|
|
70
|
-
def
|
|
71
|
-
@types_by_id = ObjectSpace.each_object( Class ).select do |obj|
|
|
72
|
-
obj < Attributor::Type
|
|
73
|
-
end.index_by(&:id)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def write_index_file( for_versions: )
|
|
86
|
+
def write_index_file(for_versions:)
|
|
77
87
|
# TODO. create a simple html file that can link to the individual versions available
|
|
78
88
|
end
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
# TODO: Change this function name to scan_default_mediatypes...
|
|
91
|
+
def collect_default_mediatypes(endpoints)
|
|
83
92
|
# We'll start by processing the rendered mediatypes
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
Set.new(endpoints.select do |endpoint|
|
|
94
|
+
endpoint.media_type && !endpoint.media_type.is_a?(Praxis::SimpleMediaType)
|
|
86
95
|
end.collect(&:media_type))
|
|
87
|
-
|
|
88
|
-
newfound = Set.new
|
|
89
|
-
found_media_types.each do |mt|
|
|
90
|
-
newfound += scan_dump_for_types( { type: mt} , processed_types )
|
|
91
|
-
end
|
|
92
|
-
# Then will process the rendered resources (noting)
|
|
93
|
-
newfound += scan_dump_for_types( dumped_resources, Set.new )
|
|
94
|
-
|
|
95
|
-
# At this point we've done a scan of the dumped resources and mediatypes.
|
|
96
|
-
# In that scan we've discovered a bunch of types, however, many of those might have appeared in the JSON
|
|
97
|
-
# rendered in just shallow mode, so it is not guaranteed that we've seen all the available types.
|
|
98
|
-
# For that we'll do a (non-shallow) dump of all the types we found, and scan them until the scans do not
|
|
99
|
-
# yield types we haven't seen before
|
|
100
|
-
while !newfound.empty? do
|
|
101
|
-
dumped = newfound.collect(&:describe)
|
|
102
|
-
processed_types += newfound
|
|
103
|
-
newfound = scan_dump_for_types( dumped, processed_types )
|
|
104
|
-
end
|
|
105
|
-
processed_types
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def scan_dump_for_types( data, processed_types )
|
|
109
|
-
newfound_types = Set.new
|
|
110
|
-
case data
|
|
111
|
-
when Array
|
|
112
|
-
data.collect{|item| newfound_types += scan_dump_for_types( item , processed_types ) }
|
|
113
|
-
when Hash
|
|
114
|
-
if data.key?(:type) && data[:type].kind_of?(Hash) && ( [:id,:name,:family] - data[:type].keys ).empty?
|
|
115
|
-
type_id = data[:type][:id]
|
|
116
|
-
unless type_id.nil? || type_id == Praxis::SimpleMediaType.id #SimpleTypes shouldn't be collected
|
|
117
|
-
unless types_by_id[type_id]
|
|
118
|
-
raise "Error! We have detected a reference to a 'Type' with id='#{type_id}' which is not derived from Attributor::Type" +
|
|
119
|
-
" Document generation cannot proceed."
|
|
120
|
-
end
|
|
121
|
-
newfound_types << types_by_id[type_id] unless processed_types.include? types_by_id[type_id]
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
data.values.map{|item| newfound_types += scan_dump_for_types( item , processed_types)}
|
|
125
|
-
end
|
|
126
|
-
newfound_types
|
|
127
96
|
end
|
|
128
97
|
|
|
129
|
-
def write_version_file(
|
|
98
|
+
def write_version_file(version)
|
|
130
99
|
# version_info = infos_by_version[version]
|
|
131
100
|
# # Hack, let's "inherit/copy" all traits of a version from the global definition
|
|
132
101
|
# # Eventually traits should be defined for a version (and inheritable from global) so we'll emulate that here
|
|
133
102
|
# version_info[:traits] = infos_by_version[:traits]
|
|
134
|
-
dumped_resources = dump_resources( resources_by_version[version] )
|
|
135
|
-
processed_types = scan_types_for_version(version, dumped_resources)
|
|
136
103
|
|
|
104
|
+
# We'll for sure include any of the default mediatypes in the endpoints for this version
|
|
105
|
+
@seen_components_for_current_version.merge(collect_default_mediatypes(resources_by_version[version]))
|
|
137
106
|
# Here we have:
|
|
138
|
-
# processed types: which includes mediatypes
|
|
107
|
+
# processed types: which includes default mediatypes for the processed endpoints
|
|
139
108
|
# processed resources for this version: resources_by_version[version]
|
|
140
109
|
|
|
141
110
|
info_object = OpenApi::InfoObject.new(version: version, api_definition_info: @infos[version])
|
|
142
111
|
# We only support a server in Praxis ... so we'll use the base path
|
|
143
|
-
server_object = OpenApi::ServerObject.new(
|
|
144
|
-
|
|
145
|
-
paths_object = OpenApi::PathsObject.new(
|
|
112
|
+
server_object = OpenApi::ServerObject.new(url: @infos[version].base_path)
|
|
113
|
+
|
|
114
|
+
paths_object = OpenApi::PathsObject.new(resources: resources_by_version[version])
|
|
146
115
|
|
|
147
116
|
full_data = {
|
|
148
|
-
openapi:
|
|
117
|
+
openapi: '3.0.2',
|
|
149
118
|
info: info_object.dump,
|
|
150
119
|
servers: [server_object.dump],
|
|
151
|
-
paths: paths_object.dump
|
|
120
|
+
paths: paths_object.dump
|
|
152
121
|
# responses: {}, #TODO!! what do we get here? the templates?...need to transform to "Responses Definitions Object"
|
|
153
122
|
# securityDefinitions: {}, # NOTE: No security definitions in Praxis
|
|
154
123
|
# security: [], # NOTE: No security definitions in Praxis
|
|
@@ -157,29 +126,25 @@ module Praxis
|
|
|
157
126
|
# Create the top level tags by:
|
|
158
127
|
# 1- First adding all the resource display names (and descriptions)
|
|
159
128
|
tags_for_resources = resources_by_version[version].collect do |resource|
|
|
160
|
-
OpenApi::TagObject.new(name: resource.display_name, description: resource.description
|
|
129
|
+
OpenApi::TagObject.new(name: resource.display_name, description: resource.description).dump
|
|
161
130
|
end
|
|
162
131
|
full_data[:tags] = tags_for_resources
|
|
163
132
|
# 2- Then adding all of the top level traits but marking them special with the x-traitTag (of Redoc)
|
|
164
|
-
tags_for_traits =
|
|
165
|
-
OpenApi::TagObject.new(name: name, description: info.description).dump.merge(
|
|
166
|
-
end
|
|
167
|
-
unless tags_for_traits.empty?
|
|
168
|
-
full_data[:tags] = full_data[:tags] + tags_for_traits
|
|
133
|
+
tags_for_traits = ApiDefinition.instance.traits.collect do |name, info|
|
|
134
|
+
OpenApi::TagObject.new(name: name, description: info.description).dump.merge('x-traitTag': true)
|
|
169
135
|
end
|
|
136
|
+
full_data[:tags] = full_data[:tags] + tags_for_traits unless tags_for_traits.empty?
|
|
137
|
+
|
|
138
|
+
# Include only MTs and Blueprints (i.e., no simple types...)
|
|
139
|
+
component_schemas = add_component_schemas(@seen_components_for_current_version.clone, {})
|
|
170
140
|
|
|
171
|
-
# Include only MTs (i.e., not custom types or simple types...)
|
|
172
|
-
component_schemas = reusable_schema_objects(processed_types.select{|t| t < Praxis::MediaType})
|
|
173
|
-
|
|
174
141
|
# 3- Then adding all of the top level Mediatypes...so we can present them at the bottom, otherwise they don't show
|
|
175
|
-
tags_for_mts = component_schemas.map do |(name,
|
|
142
|
+
tags_for_mts = component_schemas.map do |(name, _info)|
|
|
176
143
|
special_redoc_anchor = "<SchemaDefinition schemaRef=\"#/components/schemas/#{name}\" showReadOnly={true} showWriteOnly={true} />"
|
|
177
144
|
guessed_display = name.split('-').last # TODO!!!the informational hash does not seem to come with the "description" value set...hmm
|
|
178
|
-
OpenApi::TagObject.new(name: name, description: special_redoc_anchor).dump.merge(
|
|
179
|
-
end
|
|
180
|
-
unless tags_for_mts.empty?
|
|
181
|
-
full_data[:tags] = full_data[:tags] + tags_for_mts
|
|
145
|
+
OpenApi::TagObject.new(name: name, description: special_redoc_anchor).dump.merge('x-displayName': guessed_display)
|
|
182
146
|
end
|
|
147
|
+
full_data[:tags] = full_data[:tags] + tags_for_mts unless tags_for_mts.empty?
|
|
183
148
|
|
|
184
149
|
# Include all the reusable schemas in the components hash
|
|
185
150
|
full_data[:components] = {
|
|
@@ -187,25 +152,25 @@ module Praxis
|
|
|
187
152
|
}
|
|
188
153
|
|
|
189
154
|
# REDOC specific grouping of sidebar
|
|
190
|
-
resource_tags = { name: 'Resources', tags: tags_for_resources.map{|t| t[:name]} }
|
|
191
|
-
schema_tags = { name: 'Models', tags: tags_for_mts.map{|t| t[:name]} }
|
|
155
|
+
resource_tags = { name: 'Resources', tags: tags_for_resources.map { |t| t[:name] } }
|
|
156
|
+
schema_tags = { name: 'Models', tags: tags_for_mts.map { |t| t[:name] } }
|
|
192
157
|
full_data['x-tagGroups'] = [resource_tags, schema_tags]
|
|
193
158
|
|
|
194
159
|
# if parameter_object = convert_to_parameter_object( version_info[:info][:base_params] )
|
|
195
160
|
# full_data[:parameters] = parameter_object
|
|
196
161
|
# end
|
|
197
|
-
#puts JSON.pretty_generate( full_data )
|
|
162
|
+
# puts JSON.pretty_generate( full_data )
|
|
198
163
|
# Write the file
|
|
199
|
-
version_file = (
|
|
164
|
+
version_file = (version == 'n/a' ? 'unversioned' : version)
|
|
200
165
|
filename = File.join(doc_root_dir, version_file, 'openapi')
|
|
201
166
|
|
|
202
167
|
puts "Generating Open API file : #{filename} (json and yml) "
|
|
203
168
|
json_data = JSON.pretty_generate(full_data)
|
|
204
|
-
File.open(filename
|
|
205
|
-
converted_full_data = JSON.parse(
|
|
206
|
-
File.open(filename
|
|
169
|
+
File.open("#{filename}.json", 'w') { |f| f.write(json_data) }
|
|
170
|
+
converted_full_data = JSON.parse(json_data) # So symbols disappear
|
|
171
|
+
File.open("#{filename}.yml", 'w') { |f| f.write(YAML.dump(converted_full_data)) }
|
|
207
172
|
|
|
208
|
-
html
|
|
173
|
+
html = <<-HTML
|
|
209
174
|
<!DOCTYPE html>
|
|
210
175
|
<html>
|
|
211
176
|
<head>
|
|
@@ -214,7 +179,7 @@ module Praxis
|
|
|
214
179
|
<meta charset="utf-8"/>
|
|
215
180
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
216
181
|
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
|
217
|
-
|
|
182
|
+
|
|
218
183
|
<!--
|
|
219
184
|
ReDoc doesn't change outer page styles
|
|
220
185
|
-->
|
|
@@ -230,7 +195,7 @@ module Praxis
|
|
|
230
195
|
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
|
|
231
196
|
</body>
|
|
232
197
|
</html>
|
|
233
|
-
|
|
198
|
+
HTML
|
|
234
199
|
html_file = File.join(doc_root_dir, version_file, 'index.html')
|
|
235
200
|
File.write(html_file, html)
|
|
236
201
|
end
|
|
@@ -239,59 +204,59 @@ module Praxis
|
|
|
239
204
|
@doc_root_dir = File.join(@root, API_DOCS_DIRNAME)
|
|
240
205
|
|
|
241
206
|
# remove previous data (and reset the directory)
|
|
242
|
-
FileUtils.rm_rf @doc_root_dir if File.
|
|
243
|
-
FileUtils.mkdir_p @doc_root_dir unless File.
|
|
244
|
-
resources_by_version.
|
|
245
|
-
FileUtils.mkdir_p @doc_root_dir
|
|
207
|
+
FileUtils.rm_rf @doc_root_dir if File.exist?(@doc_root_dir)
|
|
208
|
+
FileUtils.mkdir_p @doc_root_dir unless File.exist? @doc_root_dir
|
|
209
|
+
resources_by_version.each_key do |version|
|
|
210
|
+
FileUtils.mkdir_p "#{@doc_root_dir}/#{version}"
|
|
246
211
|
end
|
|
247
|
-
FileUtils.mkdir_p @doc_root_dir
|
|
212
|
+
FileUtils.mkdir_p "#{@doc_root_dir}/unversioned" if resources_by_version.keys.include?('n/a')
|
|
248
213
|
end
|
|
249
214
|
|
|
250
|
-
def normalize_media_types(
|
|
215
|
+
def normalize_media_types(mtis)
|
|
251
216
|
mtis.collect do |mti|
|
|
252
|
-
|
|
253
|
-
|
|
217
|
+
MediaTypeIdentifier.load(mti).to_s
|
|
218
|
+
end
|
|
254
219
|
end
|
|
255
220
|
|
|
256
|
-
def
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
else # If it is a blueprint ... for now, it'd be through the attribute
|
|
262
|
-
type.attribute
|
|
263
|
-
end
|
|
264
|
-
accum[type.id] = the_type.as_json_schema(shallow: false)
|
|
221
|
+
def add_component_schemas(types_to_add, components_hash)
|
|
222
|
+
initial = @seen_components_for_current_version.dup
|
|
223
|
+
types_to_add.each_with_object(components_hash) do |(type), accum|
|
|
224
|
+
# For components, we want the first level to be fully dumped (only references below that)
|
|
225
|
+
accum[type.id] = OpenApi::SchemaObject.new(info: type).dump_schema(allow_ref: false, shallow: false)
|
|
265
226
|
end
|
|
227
|
+
newfound = @seen_components_for_current_version - initial
|
|
228
|
+
# Process the new types if they have discovered
|
|
229
|
+
add_component_schemas(newfound, components_hash) unless newfound.empty?
|
|
230
|
+
components_hash
|
|
266
231
|
end
|
|
267
232
|
|
|
268
|
-
def convert_to_parameter_object(
|
|
233
|
+
def convert_to_parameter_object(params)
|
|
269
234
|
# TODO!! actually convert each of them
|
|
270
|
-
puts
|
|
235
|
+
puts 'TODO! convert to parameter object'
|
|
271
236
|
params
|
|
272
237
|
end
|
|
273
238
|
|
|
274
|
-
def convert_traits_to_tags(
|
|
239
|
+
def convert_traits_to_tags(traits)
|
|
275
240
|
traits.collect do |name, info|
|
|
276
241
|
{ name: name, description: info[:description] }
|
|
277
242
|
end
|
|
278
243
|
end
|
|
279
244
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
body_type= payload[:id]
|
|
245
|
+
def dump_responses_object(responses)
|
|
246
|
+
responses.each_with_object({}) do |(_name, info), hash|
|
|
247
|
+
data = { description: info[:description] || '' }
|
|
248
|
+
if (payload = info[:payload])
|
|
249
|
+
body_type = payload[:id]
|
|
286
250
|
raise "WAIT! response payload doesn't have an existing id for the schema!!! (do an if, and describe it if so)" unless body_type
|
|
287
|
-
|
|
251
|
+
|
|
252
|
+
data[:schema] = { '$ref' => "#/definitions/#{body_type}" }
|
|
288
253
|
end
|
|
289
254
|
|
|
290
|
-
# data[:schema] = ???TODO!!
|
|
291
|
-
if headers_object = dump_response_headers_object(
|
|
255
|
+
# data[:schema] = ???TODO!!
|
|
256
|
+
if (headers_object = dump_response_headers_object(info[:headers]))
|
|
292
257
|
data[:headers] = headers_object
|
|
293
258
|
end
|
|
294
|
-
if info[:payload] && (
|
|
259
|
+
if info[:payload] && (examples_object = dump_response_examples_object(info[:payload][:examples]))
|
|
295
260
|
data[:examples] = examples_object
|
|
296
261
|
end
|
|
297
262
|
hash[info[:status]] = data
|
|
@@ -305,17 +270,17 @@ module Praxis
|
|
|
305
270
|
# end
|
|
306
271
|
# end
|
|
307
272
|
|
|
308
|
-
def dump_response_examples_object(
|
|
309
|
-
examples.each_with_object({}) do |(
|
|
273
|
+
def dump_response_examples_object(examples)
|
|
274
|
+
examples.each_with_object({}) do |(_name, info), hash|
|
|
310
275
|
hash[info[:content_type]] = info[:body]
|
|
311
276
|
end
|
|
312
277
|
end
|
|
313
278
|
|
|
314
|
-
|
|
315
|
-
def dump_resources( resources )
|
|
279
|
+
def dump_resources(resources)
|
|
316
280
|
resources.each_with_object({}) do |r, hash|
|
|
317
281
|
# Do not report undocumentable resources
|
|
318
282
|
next if r.metadata[:doc_visibility] == :none
|
|
283
|
+
|
|
319
284
|
context = [r.id]
|
|
320
285
|
resource_description = r.describe(context: context)
|
|
321
286
|
|
|
@@ -328,13 +293,12 @@ module Praxis
|
|
|
328
293
|
# skip actions with doc_visibility of :none
|
|
329
294
|
next if action.metadata[:doc_visibility] == :none
|
|
330
295
|
|
|
331
|
-
|
|
296
|
+
resource_description[:actions].find { |a| a[:name] == action_name }
|
|
332
297
|
end
|
|
333
298
|
|
|
334
299
|
hash[r.id] = resource_description
|
|
335
300
|
end
|
|
336
301
|
end
|
|
337
|
-
|
|
338
302
|
end
|
|
339
303
|
end
|
|
340
304
|
end
|