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,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'schema_object'
|
|
2
4
|
|
|
3
5
|
module Praxis
|
|
@@ -6,7 +8,8 @@ module Praxis
|
|
|
6
8
|
class ParameterObject
|
|
7
9
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameter-object
|
|
8
10
|
attr_reader :location, :name, :is_required, :info
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
def initialize(location:, name:, is_required:, info:)
|
|
10
13
|
@location = location
|
|
11
14
|
@name = name
|
|
12
15
|
@info = info
|
|
@@ -25,39 +28,39 @@ module Praxis
|
|
|
25
28
|
# style
|
|
26
29
|
# explode
|
|
27
30
|
# allowReserved
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
# Now merge the rest schema and example
|
|
30
33
|
# schema
|
|
31
34
|
# example
|
|
32
35
|
# examples (Example and Examples are mutually exclusive)
|
|
33
36
|
schema = SchemaObject.new(info: info)
|
|
34
37
|
h[:schema] = schema.dump_schema
|
|
35
|
-
#
|
|
38
|
+
# NOTE: we do not support the 'content' key...we always use schema
|
|
36
39
|
h[:example] = schema.dump_example
|
|
37
40
|
h
|
|
38
41
|
end
|
|
39
42
|
|
|
40
|
-
def self.process_parameters(
|
|
43
|
+
def self.process_parameters(action)
|
|
41
44
|
output = []
|
|
42
|
-
# An array, with one hash per param inside
|
|
45
|
+
# An array, with one hash per param inside
|
|
43
46
|
if action.headers
|
|
44
|
-
(action.headers.attributes||{}).each_with_object(output) do |(name, info), out|
|
|
45
|
-
out << ParameterObject.new(
|
|
47
|
+
(action.headers.attributes || {}).each_with_object(output) do |(name, info), out|
|
|
48
|
+
out << ParameterObject.new(location: 'header', name: name, is_required: info.options[:required], info: info).dump
|
|
46
49
|
end
|
|
47
50
|
end
|
|
48
|
-
|
|
51
|
+
|
|
49
52
|
if action.params
|
|
50
53
|
route_params = \
|
|
51
|
-
|
|
54
|
+
if action.route
|
|
55
|
+
action.route.path.named_captures.keys.collect(&:to_sym)
|
|
56
|
+
else
|
|
52
57
|
warn "Warning: No routes defined for action #{action.name}"
|
|
53
58
|
[]
|
|
54
|
-
else
|
|
55
|
-
action.route.path.named_captures.keys.collect(&:to_sym)
|
|
56
59
|
end
|
|
57
|
-
(action.params.attributes||{}).each_with_object(output) do |(name, info), out|
|
|
60
|
+
(action.params.attributes || {}).each_with_object(output) do |(name, info), out|
|
|
58
61
|
in_type = route_params.include?(name) ? :path : :query
|
|
59
|
-
is_required =
|
|
60
|
-
out << ParameterObject.new(
|
|
62
|
+
is_required = in_type == :path ? true : info.options[:required]
|
|
63
|
+
out << ParameterObject.new(location: in_type, name: name, is_required: is_required, info: info).dump
|
|
61
64
|
end
|
|
62
65
|
end
|
|
63
66
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'operation_object'
|
|
2
4
|
module Praxis
|
|
3
5
|
module Docs
|
|
4
6
|
module OpenApi
|
|
5
7
|
class PathsObject
|
|
6
8
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#paths-object
|
|
7
9
|
attr_reader :resources, :paths
|
|
10
|
+
|
|
8
11
|
def initialize(resources:)
|
|
9
12
|
@resources = resources
|
|
10
13
|
# A hash with keys of paths, and values of hash
|
|
@@ -15,18 +18,17 @@ module Praxis
|
|
|
15
18
|
# "post": { ...}
|
|
16
19
|
# "/humans": {
|
|
17
20
|
# "get": {...},
|
|
18
|
-
@paths = Hash.new {|h,k| h[k] = {} }
|
|
21
|
+
@paths = Hash.new { |h, k| h[k] = {} }
|
|
19
22
|
end
|
|
20
23
|
|
|
21
|
-
|
|
22
24
|
def dump
|
|
23
25
|
resources.each do |resource|
|
|
24
|
-
compute_resource_paths(
|
|
26
|
+
compute_resource_paths(resource)
|
|
25
27
|
end
|
|
26
28
|
paths
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
def compute_resource_paths(
|
|
31
|
+
def compute_resource_paths(resource)
|
|
30
32
|
id = resource.id
|
|
31
33
|
# fill in the paths hash with a key for each path for each action/route
|
|
32
34
|
resource.actions.each do |action_name, action|
|
|
@@ -38,15 +40,15 @@ module Praxis
|
|
|
38
40
|
path_entry = paths[templetized_path]
|
|
39
41
|
# Let's fill in verb stuff within the working hash
|
|
40
42
|
raise "VERB #{_verb} already defined for #{id}!?!?!" if path_entry[verb]
|
|
41
|
-
|
|
43
|
+
|
|
42
44
|
action_uid = "action-#{action_name}-#{id}"
|
|
43
45
|
# Add a tag matching the resource name (hoping all actions of a resource are grouped)
|
|
44
46
|
action_tags = [resource.display_name]
|
|
45
|
-
path_entry[verb] = OperationObject.new(
|
|
47
|
+
path_entry[verb] = OperationObject.new(id: action_uid, url: url, action: action, tags: action_tags).dump
|
|
46
48
|
end
|
|
47
|
-
# For each path, we can further annotate with
|
|
49
|
+
# For each path, we can further annotate with
|
|
48
50
|
# servers
|
|
49
|
-
# parameters
|
|
51
|
+
# parameters
|
|
50
52
|
# But we don't have that concept in praxis
|
|
51
53
|
end
|
|
52
54
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'schema_object'
|
|
2
4
|
|
|
3
5
|
module Praxis
|
|
@@ -5,7 +7,8 @@ module Praxis
|
|
|
5
7
|
module OpenApi
|
|
6
8
|
class RequestBodyObject
|
|
7
9
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#request-body-object
|
|
8
|
-
attr_reader :attribute
|
|
10
|
+
attr_reader :attribute
|
|
11
|
+
|
|
9
12
|
def initialize(attribute:)
|
|
10
13
|
@attribute = attribute
|
|
11
14
|
end
|
|
@@ -18,18 +21,18 @@ module Praxis
|
|
|
18
21
|
# OpenApi wants a set of bodies per MediaType/Content-Type
|
|
19
22
|
# For us there's really only one schema (regardless of encoding)...
|
|
20
23
|
# so we'll show all the supported MTs...but repeating the schema
|
|
21
|
-
#dumped_schema = SchemaObject.new(info: attribute).dump_schema
|
|
24
|
+
# dumped_schema = SchemaObject.new(info: attribute).dump_schema
|
|
22
25
|
|
|
23
26
|
example_handlers = if attribute.type < Praxis::Types::MultipartArray
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
h[:content] = MediaTypeObject.create_content_attribute_helper(type: attribute.type,
|
|
32
|
-
example_payload: attribute.example(nil),
|
|
27
|
+
ident = MediaTypeIdentifier.load('multipart/form-data')
|
|
28
|
+
[{ ident.to_s => 'plain' }] # Multipart content type, but with the plain renderer (so there's no modification)
|
|
29
|
+
else
|
|
30
|
+
# TODO: We could run it through other handlers I guess...if they're registered
|
|
31
|
+
[{ 'application/json' => 'json' }]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
h[:content] = MediaTypeObject.create_content_attribute_helper(type: attribute.type,
|
|
35
|
+
example_payload: attribute.example(nil),
|
|
33
36
|
example_handlers: example_handlers)
|
|
34
37
|
# # Key string (of MT) , value MTObject
|
|
35
38
|
# content_hash = info[:examples].each_with_object({}) do |(handler, example_hash),accum|
|
|
@@ -43,8 +46,6 @@ module Praxis
|
|
|
43
46
|
# h[:content] = content_hash
|
|
44
47
|
h
|
|
45
48
|
end
|
|
46
|
-
|
|
47
|
-
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'media_type_object'
|
|
2
4
|
|
|
3
5
|
module Praxis
|
|
@@ -6,33 +8,39 @@ module Praxis
|
|
|
6
8
|
class ResponseObject
|
|
7
9
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#response-object
|
|
8
10
|
attr_reader :info
|
|
11
|
+
|
|
9
12
|
def initialize(info:)
|
|
10
13
|
@info = info
|
|
11
14
|
default_handlers = ApiDefinition.instance.info.produces
|
|
12
|
-
@output_handlers = Praxis::Application.instance.handlers.select do |k,
|
|
15
|
+
@output_handlers = Praxis::Application.instance.handlers.select do |k, _v|
|
|
13
16
|
default_handlers.include?(k)
|
|
14
17
|
end
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
def dump_response_headers_object(
|
|
18
|
-
headers.each_with_object({}) do |(name,data),accum|
|
|
19
|
-
# each header comes from Praxis::ResponseDefinition
|
|
20
|
+
def dump_response_headers_object(headers)
|
|
21
|
+
headers.each_with_object({}) do |(name, data), accum|
|
|
22
|
+
# each header comes from Praxis::ResponseDefinition
|
|
20
23
|
# the keys are the header names, and value can be:
|
|
21
24
|
# "true" => means it only needs to exist
|
|
22
25
|
# String => which means that it has to fully match
|
|
23
26
|
# Regex => which means it has to regexp match it
|
|
24
27
|
|
|
25
28
|
# Get the schema from the type (defaulting to string in case the type doesn't have the as_json_schema defined)
|
|
26
|
-
schema =
|
|
29
|
+
schema = begin
|
|
30
|
+
data[:attribute].type.as_json_schema
|
|
31
|
+
rescue StandardError
|
|
32
|
+
{ type: :string }
|
|
33
|
+
end
|
|
27
34
|
hash = { description: data[:description] || '', schema: schema }
|
|
28
|
-
# Note, our Headers in response definition are not full types...they're basically only
|
|
35
|
+
# Note, our Headers in response definition are not full types...they're basically only
|
|
29
36
|
# strings, which can either match anything, match the exact word or match a regex
|
|
30
37
|
# they don't even have a description...
|
|
31
38
|
data_value = data[:value]
|
|
32
|
-
|
|
39
|
+
case data_value
|
|
40
|
+
when String
|
|
33
41
|
hash[:pattern] = "^#{data_value}$" # Exact String match
|
|
34
|
-
|
|
35
|
-
sanitized_pattern = data_value.inspect[1..-2] #inspect returns enclosing '/' characters
|
|
42
|
+
when Regexp
|
|
43
|
+
sanitized_pattern = data_value.inspect[1..-2] # inspect returns enclosing '/' characters
|
|
36
44
|
hash[:pattern] = sanitized_pattern
|
|
37
45
|
end
|
|
38
46
|
|
|
@@ -41,10 +49,10 @@ module Praxis
|
|
|
41
49
|
end
|
|
42
50
|
|
|
43
51
|
def dump
|
|
44
|
-
data = {
|
|
52
|
+
data = {
|
|
45
53
|
description: info.description || ''
|
|
46
54
|
}
|
|
47
|
-
if headers_object = dump_response_headers_object(
|
|
55
|
+
if (headers_object = dump_response_headers_object(info.headers))
|
|
48
56
|
data[:headers] = headers_object
|
|
49
57
|
end
|
|
50
58
|
|
|
@@ -52,12 +60,13 @@ module Praxis
|
|
|
52
60
|
|
|
53
61
|
identifier = MediaTypeIdentifier.load(info.media_type.identifier)
|
|
54
62
|
example_handlers = @output_handlers.each_with_object([]) do |(name, _handler), accum|
|
|
55
|
-
accum.push({ (identifier + name).to_s => name})
|
|
63
|
+
accum.push({ (identifier + name).to_s => name })
|
|
56
64
|
end
|
|
57
65
|
data[:content] = MediaTypeObject.create_content_attribute_helper(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
type: info.media_type,
|
|
67
|
+
example_payload: info.example(nil),
|
|
68
|
+
example_handlers: example_handlers
|
|
69
|
+
)
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
# if payload = info[:payload]
|
|
@@ -66,12 +75,9 @@ module Praxis
|
|
|
66
75
|
# data[:schema] = {"$ref" => "#/definitions/#{body_type}" }
|
|
67
76
|
# end
|
|
68
77
|
|
|
69
|
-
|
|
70
78
|
# TODO: we do not support 'links'
|
|
71
79
|
data
|
|
72
80
|
end
|
|
73
|
-
|
|
74
|
-
|
|
75
81
|
end
|
|
76
82
|
end
|
|
77
83
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'response_object'
|
|
2
4
|
|
|
3
5
|
module Praxis
|
|
@@ -6,11 +8,11 @@ module Praxis
|
|
|
6
8
|
class ResponsesObject
|
|
7
9
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responses-object
|
|
8
10
|
attr_reader :responses
|
|
11
|
+
|
|
9
12
|
def initialize(responses:)
|
|
10
13
|
@responses = responses
|
|
11
14
|
end
|
|
12
15
|
|
|
13
|
-
|
|
14
16
|
def dump
|
|
15
17
|
# {
|
|
16
18
|
# "200": {
|
|
@@ -1,35 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Praxis
|
|
2
4
|
module Docs
|
|
3
5
|
module OpenApi
|
|
4
6
|
class SchemaObject
|
|
5
7
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schema-object
|
|
6
|
-
attr_reader :type
|
|
8
|
+
attr_reader :type
|
|
9
|
+
|
|
7
10
|
def initialize(info:)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
@attribute_options = {}
|
|
12
|
+
|
|
13
|
+
# info could be an attribute ... or a type
|
|
14
|
+
if info.is_a?(Attributor::Attribute)
|
|
15
|
+
@type = info.type
|
|
16
|
+
# Save the options that might be attached to the attribute, to add them to the type schema later
|
|
17
|
+
@attribute_options = info.options
|
|
11
18
|
else
|
|
12
19
|
@type = info
|
|
13
20
|
end
|
|
21
|
+
|
|
22
|
+
# Mediatypes have the description method, lower types don't
|
|
23
|
+
@attribute_options[:description] = @type.description if @type.respond_to?(:description)
|
|
24
|
+
@collection = type.respond_to?(:member_type)
|
|
14
25
|
end
|
|
15
26
|
|
|
16
27
|
def dump_example
|
|
17
|
-
ex =
|
|
18
|
-
if attribute
|
|
19
|
-
attribute.example
|
|
20
|
-
else
|
|
21
|
-
type.example
|
|
22
|
-
end
|
|
28
|
+
ex = type.example
|
|
23
29
|
ex.respond_to?(:dump) ? ex.dump : ex
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
def dump_schema
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
def dump_schema(shallow: false, allow_ref: false)
|
|
33
|
+
# We will dump schemas for mediatypes by simply creating a reference to the components' section
|
|
34
|
+
if type < Attributor::Container
|
|
35
|
+
if (type < Praxis::Blueprint || type < Attributor::Model) && allow_ref && !type.anonymous?
|
|
36
|
+
# TODO: Do we even need a description?
|
|
37
|
+
h = @attribute_options[:description] ? { 'description' => @attribute_options[:description] } : {}
|
|
38
|
+
|
|
39
|
+
Praxis::Docs::OpenApiGenerator.instance.register_seen_component(type)
|
|
40
|
+
h.merge!('$ref' => "#/components/schemas/#{type.id}")
|
|
41
|
+
elsif @collection
|
|
42
|
+
items = OpenApi::SchemaObject.new(info: type.member_type).dump_schema(allow_ref: allow_ref, shallow: false)
|
|
43
|
+
h = @attribute_options[:description] ? { 'description' => @attribute_options[:description] } : {}
|
|
44
|
+
h.merge!(type: 'array', items: items)
|
|
45
|
+
else # Attributor::Struct, etc
|
|
46
|
+
props = type.attributes.transform_values do |definition|
|
|
47
|
+
OpenApi::SchemaObject.new(info: definition).dump_schema(allow_ref: true, shallow: shallow)
|
|
48
|
+
end
|
|
49
|
+
h = { type: :object, properties: props } # TODO: Example?
|
|
50
|
+
end
|
|
29
51
|
else
|
|
30
|
-
|
|
52
|
+
# OpenApi::SchemaObject.new(info:target).dump_schema(allow_ref: allow_ref, shallow: shallow)
|
|
53
|
+
# TODO...we need to make sure we can use refs in the underlying components after the first level...
|
|
54
|
+
# ... maybe we need to loop over the attributes if it's an object/struct?...
|
|
55
|
+
h = type.as_json_schema(shallow: shallow, example: nil, attribute_options: @attribute_options)
|
|
31
56
|
end
|
|
32
|
-
|
|
57
|
+
|
|
58
|
+
# Tag on OpenAPI specific requirements that aren't already added in the underlying JSON schema model
|
|
59
|
+
# Nullable: (it seems we need to ensure there is a null option to the enum, if there is one)
|
|
60
|
+
if @attribute_options[:null]
|
|
61
|
+
h[:nullable] = @attribute_options[:null]
|
|
62
|
+
h[:enum] = h[:enum] + [nil] if h[:enum] && !h[:enum].include?(nil)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
h
|
|
66
|
+
|
|
67
|
+
# # TODO: FIXME: return a generic object type if the passed info was weird.
|
|
33
68
|
# return { type: :object } unless info
|
|
34
69
|
|
|
35
70
|
# h = {
|
|
@@ -41,7 +76,7 @@ module Praxis
|
|
|
41
76
|
# h[:default] = info[:default] if info[:default]
|
|
42
77
|
# h[:pattern] = info[:regexp] if info[:regexp]
|
|
43
78
|
# # TODO: there are other possible things we can do..maximum, minimum...etc
|
|
44
|
-
|
|
79
|
+
|
|
45
80
|
# if h[:type] == :array
|
|
46
81
|
# # FIXME: ... hack it for MultiPart arrays...where there's no member attr
|
|
47
82
|
# member_type = info[:type][:member_attribute]
|
|
@@ -51,27 +86,25 @@ module Praxis
|
|
|
51
86
|
# h[:items] = SchemaObject.new(info: member_type ).dump_schema
|
|
52
87
|
# end
|
|
53
88
|
# h
|
|
54
|
-
rescue => e
|
|
89
|
+
rescue StandardError => e
|
|
55
90
|
puts "Error dumping schema #{e}"
|
|
56
91
|
end
|
|
57
|
-
|
|
58
|
-
def convert_family_to_json_type(
|
|
92
|
+
|
|
93
|
+
def convert_family_to_json_type(praxis_type)
|
|
59
94
|
case praxis_type[:family].to_sym
|
|
60
95
|
when :string
|
|
61
96
|
:string
|
|
62
97
|
when :hash
|
|
63
98
|
:object
|
|
64
|
-
when :array #Warning! Multipart types are arrays!
|
|
99
|
+
when :array # Warning! Multipart types are arrays!
|
|
65
100
|
:array
|
|
66
101
|
when :numeric
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
:integer
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
:number
|
|
74
|
-
end
|
|
102
|
+
jtypes = {
|
|
103
|
+
'Attributor-Integer' => :integer,
|
|
104
|
+
'Attributor-BigDecimal' => :integer,
|
|
105
|
+
'Attributor-Float' => :number
|
|
106
|
+
}
|
|
107
|
+
jtypes[praxis_type[:id]]
|
|
75
108
|
when :temporal
|
|
76
109
|
:string
|
|
77
110
|
when :boolean
|
|
@@ -80,7 +113,6 @@ module Praxis
|
|
|
80
113
|
raise "Unknown praxis family type: #{praxis_type[:family]}"
|
|
81
114
|
end
|
|
82
115
|
end
|
|
83
|
-
|
|
84
116
|
end
|
|
85
117
|
end
|
|
86
118
|
end
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Praxis
|
|
2
4
|
module Docs
|
|
3
5
|
module OpenApi
|
|
4
6
|
class ServerObject
|
|
5
7
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#server-object
|
|
6
8
|
attr_reader :url, :description, :variables
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
def initialize(url:, description: nil, variables: [])
|
|
8
11
|
@url = url
|
|
9
12
|
@description = description
|
|
10
13
|
@variables = variables
|
|
@@ -12,7 +15,7 @@ module Praxis
|
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def dump
|
|
15
|
-
result = {url: url}
|
|
18
|
+
result = { url: url }
|
|
16
19
|
result[:description] = description if description
|
|
17
20
|
result[:variables] = variables unless variables.empty?
|
|
18
21
|
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Praxis
|
|
2
4
|
module Docs
|
|
3
5
|
module OpenApi
|
|
4
6
|
class TagObject
|
|
5
7
|
attr_reader :name, :description
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
def initialize(name:, description:)
|
|
7
10
|
@name = name
|
|
8
11
|
@description = description
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
def dump
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#externalDocs: ???,
|
|
16
|
-
|
|
15
|
+
h = description ? { description: description } : {}
|
|
16
|
+
h.merge(
|
|
17
|
+
name: name
|
|
18
|
+
# externalDocs: ???,
|
|
19
|
+
)
|
|
17
20
|
end
|
|
18
21
|
end
|
|
19
22
|
end
|