praxis 2.0.pre.17 → 2.0.pre.21
Sign up to get free protection for your applications and to get access to all the features.
- 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
|