praxis 2.0.pre.8 → 2.0.pre.13
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/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -3
- data/CHANGELOG.md +33 -0
- data/TODO.md +1 -4
- data/bin/praxis +67 -12
- data/lib/praxis.rb +10 -3
- data/lib/praxis/action_definition.rb +15 -13
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +0 -7
- data/lib/praxis/api_general_info.rb +1 -1
- data/lib/praxis/application.rb +6 -2
- data/lib/praxis/blueprint.rb +357 -0
- data/lib/praxis/bootloader.rb +9 -3
- data/lib/praxis/bootloader_stages/environment.rb +16 -13
- data/lib/praxis/collection.rb +1 -11
- data/lib/praxis/config_hash.rb +44 -0
- data/lib/praxis/docs/{openapi → open_api}/info_object.rb +18 -10
- data/lib/praxis/docs/{openapi → open_api}/media_type_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/operation_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/parameter_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/paths_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/request_body_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/response_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/responses_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/schema_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/server_object.rb +0 -0
- data/lib/praxis/docs/{openapi → open_api}/tag_object.rb +0 -0
- data/lib/praxis/docs/open_api_generator.rb +91 -6
- data/lib/praxis/endpoint_definition.rb +273 -0
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +182 -58
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +3 -2
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +47 -56
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +153 -0
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +20 -8
- data/lib/praxis/extensions/field_expansion.rb +3 -36
- data/lib/praxis/extensions/pagination.rb +5 -32
- data/lib/praxis/extensions/pagination/ordering_params.rb +1 -1
- data/lib/praxis/extensions/pagination/pagination_params.rb +6 -4
- data/lib/praxis/field_expander.rb +90 -0
- data/lib/praxis/finalizable.rb +34 -0
- data/lib/praxis/mapper/active_model_compat.rb +4 -0
- data/lib/praxis/mapper/resource.rb +18 -2
- data/lib/praxis/mapper/selector_generator.rb +2 -1
- data/lib/praxis/mapper/sequel_compat.rb +7 -0
- data/lib/praxis/media_type.rb +3 -68
- data/lib/praxis/plugin_concern.rb +1 -1
- data/lib/praxis/plugins/mapper_plugin.rb +24 -15
- data/lib/praxis/plugins/pagination_plugin.rb +34 -4
- data/lib/praxis/renderer.rb +88 -0
- data/lib/praxis/request.rb +1 -1
- data/lib/praxis/resource_definition.rb +2 -311
- data/lib/praxis/response_definition.rb +2 -10
- data/lib/praxis/response_template.rb +3 -3
- data/lib/praxis/router.rb +2 -2
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/tasks/api_docs.rb +17 -64
- data/lib/praxis/tasks/routes.rb +1 -1
- data/lib/praxis/types/media_type_common.rb +1 -11
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +0 -1
- data/spec/functional_spec.rb +5 -9
- data/spec/praxis/action_definition_spec.rb +12 -20
- data/spec/praxis/blueprint_spec.rb +373 -0
- data/spec/praxis/bootloader_spec.rb +10 -2
- data/spec/praxis/collection_spec.rb +0 -13
- data/spec/praxis/config_hash_spec.rb +64 -0
- data/spec/praxis/{resource_definition_spec.rb → endpoint_definition_spec.rb} +37 -64
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +249 -168
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +25 -6
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +190 -8
- data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +140 -0
- data/spec/praxis/extensions/field_expansion_spec.rb +5 -24
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +1 -1
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +1 -1
- data/spec/praxis/extensions/support/spec_resources_active_model.rb +1 -1
- data/spec/praxis/field_expander_spec.rb +149 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +1 -1
- data/spec/praxis/media_type_identifier_spec.rb +5 -4
- data/spec/praxis/media_type_spec.rb +4 -93
- data/spec/praxis/renderer_spec.rb +188 -0
- data/spec/praxis/response_definition_spec.rb +0 -31
- data/spec/praxis/response_spec.rb +1 -1
- data/spec/praxis/router_spec.rb +8 -8
- data/spec/praxis/routing_config_spec.rb +3 -3
- data/spec/spec_app/app/controllers/instances.rb +13 -7
- data/spec/spec_app/design/media_types/instance.rb +1 -19
- data/spec/spec_app/design/media_types/volume.rb +1 -1
- data/spec/spec_app/design/media_types/volume_snapshot.rb +2 -14
- data/spec/spec_app/design/resources/instances.rb +5 -8
- data/spec/spec_app/design/resources/volume_snapshots.rb +1 -1
- data/spec/spec_app/design/resources/volumes.rb +1 -1
- data/spec/support/spec_authorization_plugin.rb +1 -1
- data/spec/support/spec_blueprints.rb +72 -0
- data/spec/support/{spec_resource_definitions.rb → spec_endpoint_definitions.rb} +2 -2
- data/spec/support/spec_media_types.rb +6 -26
- data/tasks/thor/app.rb +8 -34
- data/tasks/thor/example.rb +51 -285
- data/tasks/thor/model.rb +40 -0
- data/tasks/thor/scaffold.rb +117 -0
- data/tasks/thor/templates/generator/empty_app/.gitignore +0 -1
- data/tasks/thor/templates/generator/empty_app/Gemfile +7 -23
- data/tasks/thor/templates/generator/empty_app/README.md +1 -1
- data/tasks/thor/templates/generator/empty_app/Rakefile +4 -13
- data/tasks/thor/templates/generator/empty_app/{design/response_templates → app/v1/resources}/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/{design/response_templates → app/v1/resources}/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/config/environment.rb +26 -17
- data/tasks/thor/templates/generator/empty_app/{design/v1/resources → config/initializers}/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/{design/v1/resources → config/initializers}/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/endpoints/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/design/v1/endpoints/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/docs/.empty_directory +0 -0
- data/tasks/thor/templates/generator/empty_app/docs/.gitkeep +0 -0
- data/tasks/thor/templates/generator/empty_app/spec/spec_helper.rb +14 -9
- data/tasks/thor/templates/generator/example_app/.gitignore +1 -0
- data/tasks/thor/templates/generator/example_app/Gemfile +19 -0
- data/tasks/thor/templates/generator/example_app/Rakefile +61 -0
- data/tasks/thor/templates/generator/example_app/app/models/user.rb +6 -0
- data/tasks/thor/templates/generator/example_app/app/v1/concerns/controller_base.rb +24 -0
- data/tasks/thor/templates/generator/example_app/app/v1/controllers/users.rb +17 -0
- data/tasks/thor/templates/generator/example_app/app/v1/resources/base.rb +11 -0
- data/tasks/thor/templates/generator/example_app/app/v1/resources/user.rb +25 -0
- data/tasks/thor/templates/generator/example_app/config.ru +30 -0
- data/tasks/thor/templates/generator/example_app/config/environment.rb +41 -0
- data/tasks/thor/templates/generator/example_app/db/migrate/20201010101010_create_users_table.rb +12 -0
- data/tasks/thor/templates/generator/example_app/db/seeds.rb +6 -0
- data/tasks/thor/templates/generator/example_app/design/api.rb +18 -0
- data/tasks/thor/templates/generator/example_app/design/v1/endpoints/users.rb +37 -0
- data/tasks/thor/templates/generator/example_app/design/v1/media_types/user.rb +21 -0
- data/tasks/thor/templates/generator/example_app/spec/helpers/database_helper.rb +20 -0
- data/tasks/thor/templates/generator/example_app/spec/spec_helper.rb +42 -0
- data/tasks/thor/templates/generator/example_app/spec/v1/controllers/users_spec.rb +37 -0
- data/tasks/thor/templates/generator/scaffold/design/endpoints/collection.rb +98 -0
- data/tasks/thor/templates/generator/scaffold/design/media_types/item.rb +18 -0
- data/tasks/thor/templates/generator/scaffold/implementation/controllers/collection.rb +77 -0
- data/tasks/thor/templates/generator/scaffold/implementation/resources/base.rb +11 -0
- data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +45 -0
- data/tasks/thor/templates/generator/scaffold/models/active_record.rb +6 -0
- data/tasks/thor/templates/generator/scaffold/models/sequel.rb +6 -0
- metadata +64 -136
- data/lib/api_browser/.bowerrc +0 -3
- data/lib/api_browser/.editorconfig +0 -21
- data/lib/api_browser/Gruntfile.js +0 -581
- data/lib/api_browser/app/index.html +0 -59
- data/lib/api_browser/app/js/app.js +0 -48
- data/lib/api_browser/app/js/controllers/action.js +0 -47
- data/lib/api_browser/app/js/controllers/controller.js +0 -10
- data/lib/api_browser/app/js/controllers/menu.js +0 -93
- data/lib/api_browser/app/js/controllers/trait.js +0 -10
- data/lib/api_browser/app/js/controllers/type.js +0 -24
- data/lib/api_browser/app/js/directives/attribute_description.js +0 -56
- data/lib/api_browser/app/js/directives/attribute_table.js +0 -28
- data/lib/api_browser/app/js/directives/conditional_requirements.js +0 -13
- data/lib/api_browser/app/js/directives/fixed_if_fits.js +0 -38
- data/lib/api_browser/app/js/directives/highlight.js +0 -14
- data/lib/api_browser/app/js/directives/menu_item.js +0 -59
- data/lib/api_browser/app/js/directives/no_container.js +0 -8
- data/lib/api_browser/app/js/directives/readable_list.js +0 -87
- data/lib/api_browser/app/js/directives/request_examples.js +0 -31
- data/lib/api_browser/app/js/directives/type_placeholder.js +0 -30
- data/lib/api_browser/app/js/directives/url.js +0 -15
- data/lib/api_browser/app/js/factories/Configuration.js +0 -12
- data/lib/api_browser/app/js/factories/Documentation.js +0 -61
- data/lib/api_browser/app/js/factories/Example.js +0 -51
- data/lib/api_browser/app/js/factories/PageInfo.js +0 -9
- data/lib/api_browser/app/js/factories/normalize_attributes.js +0 -20
- data/lib/api_browser/app/js/factories/prepare_template.js +0 -15
- data/lib/api_browser/app/js/factories/template_for.js +0 -128
- data/lib/api_browser/app/js/filters/attribute_name.js +0 -10
- data/lib/api_browser/app/js/filters/friendly_json.js +0 -5
- data/lib/api_browser/app/js/filters/has_requirement.js +0 -14
- data/lib/api_browser/app/js/filters/header_info.js +0 -9
- data/lib/api_browser/app/js/filters/is_empty.js +0 -8
- data/lib/api_browser/app/js/filters/markdown.js +0 -6
- data/lib/api_browser/app/js/filters/resource_name.js +0 -5
- data/lib/api_browser/app/js/filters/tag_requirement.js +0 -13
- data/lib/api_browser/app/sass/modules/_body.scss +0 -40
- data/lib/api_browser/app/sass/modules/_cloke.scss +0 -8
- data/lib/api_browser/app/sass/modules/_header.scss +0 -10
- data/lib/api_browser/app/sass/modules/_nav.scss +0 -7
- data/lib/api_browser/app/sass/modules/_sidebar.scss +0 -134
- data/lib/api_browser/app/sass/modules/_switch.scss +0 -55
- data/lib/api_browser/app/sass/modules/_table.scss +0 -13
- data/lib/api_browser/app/sass/praxis.scss +0 -70
- data/lib/api_browser/app/sass/variables/_bootstrap-variables.scss +0 -774
- data/lib/api_browser/app/views/action.html +0 -97
- data/lib/api_browser/app/views/builtin/field-selector.html +0 -24
- data/lib/api_browser/app/views/controller.html +0 -55
- data/lib/api_browser/app/views/directives/attribute_description.html +0 -2
- data/lib/api_browser/app/views/directives/attribute_description/default.html +0 -2
- data/lib/api_browser/app/views/directives/attribute_description/example.html +0 -13
- data/lib/api_browser/app/views/directives/attribute_description/headers.html +0 -8
- data/lib/api_browser/app/views/directives/attribute_description/member_options.html +0 -4
- data/lib/api_browser/app/views/directives/attribute_description/values.html +0 -14
- data/lib/api_browser/app/views/directives/attribute_table.html +0 -17
- data/lib/api_browser/app/views/directives/menu_item.html +0 -8
- data/lib/api_browser/app/views/directives/url.html +0 -3
- data/lib/api_browser/app/views/examples/general.html +0 -26
- data/lib/api_browser/app/views/home.html +0 -5
- data/lib/api_browser/app/views/layout.html +0 -8
- data/lib/api_browser/app/views/menu.html +0 -42
- data/lib/api_browser/app/views/navbar.html +0 -9
- data/lib/api_browser/app/views/trait.html +0 -13
- data/lib/api_browser/app/views/type.html +0 -6
- data/lib/api_browser/app/views/type/details.html +0 -33
- data/lib/api_browser/app/views/types/embedded/array.html +0 -2
- data/lib/api_browser/app/views/types/embedded/default.html +0 -12
- data/lib/api_browser/app/views/types/embedded/field-selector.html +0 -13
- data/lib/api_browser/app/views/types/embedded/links.html +0 -11
- data/lib/api_browser/app/views/types/embedded/requirements.html +0 -6
- data/lib/api_browser/app/views/types/embedded/single_req.html +0 -9
- data/lib/api_browser/app/views/types/embedded/struct.html +0 -14
- data/lib/api_browser/app/views/types/label/link.html +0 -1
- data/lib/api_browser/app/views/types/label/primitive.html +0 -1
- data/lib/api_browser/app/views/types/label/primitive_collection.html +0 -1
- data/lib/api_browser/app/views/types/label/type.html +0 -1
- data/lib/api_browser/app/views/types/label/type_collection.html +0 -1
- data/lib/api_browser/app/views/types/main/array.html +0 -22
- data/lib/api_browser/app/views/types/main/default.html +0 -23
- data/lib/api_browser/app/views/types/main/hash.html +0 -23
- data/lib/api_browser/app/views/types/standalone/array.html +0 -3
- data/lib/api_browser/app/views/types/standalone/default.html +0 -18
- data/lib/api_browser/app/views/types/standalone/struct.html +0 -2
- data/lib/api_browser/bower_template.json +0 -41
- data/lib/api_browser/package-lock.json +0 -7110
- data/lib/api_browser/package.json +0 -43
- data/lib/praxis/docs/generator.rb +0 -243
- data/lib/praxis/docs/link_builder.rb +0 -30
- data/lib/praxis/links.rb +0 -135
- data/lib/praxis/types/multipart.rb +0 -109
- data/spec/api_browser/directives/type_placeholder_spec.js +0 -134
- data/spec/api_browser/factories/configuration_spec.js +0 -32
- data/spec/api_browser/factories/documentation_spec.js +0 -100
- data/spec/api_browser/factories/normalize_attributes_spec.js +0 -92
- data/spec/api_browser/factories/template_for_spec.js +0 -67
- data/spec/api_browser/filters/attribute_name_spec.js +0 -23
- data/spec/praxis/types/multipart_spec.rb +0 -112
- data/tasks/thor/templates/generator/empty_app/.rspec +0 -1
- data/tasks/thor/templates/generator/empty_app/Guardfile +0 -3
- data/tasks/thor/templates/generator/empty_app/config/rainbows.rb +0 -57
- data/tasks/thor/templates/generator/empty_app/docs/app.js +0 -1
- data/tasks/thor/templates/generator/empty_app/docs/styles.scss +0 -3
data/lib/praxis/request.rb
CHANGED
|
@@ -82,7 +82,7 @@ module Praxis
|
|
|
82
82
|
PATH_VERSION_PREFIX
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
# DEPRECATED: remove with
|
|
85
|
+
# DEPRECATED: remove with EndpointDefinition.version using: :path
|
|
86
86
|
PATH_VERSION_MATCHER = %r{^#{self.path_version_prefix}(?<version>[^\/]+)\/}.freeze
|
|
87
87
|
|
|
88
88
|
def path_version_matcher
|
|
@@ -1,312 +1,3 @@
|
|
|
1
|
-
require 'active_support/concern'
|
|
2
|
-
require 'active_support/inflector'
|
|
3
1
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
extend ActiveSupport::Concern
|
|
7
|
-
|
|
8
|
-
DEFAULT_RESOURCE_HREF_ACTION = :show
|
|
9
|
-
|
|
10
|
-
included do
|
|
11
|
-
@version = 'n/a'.freeze
|
|
12
|
-
@actions = Hash.new
|
|
13
|
-
@responses = Hash.new
|
|
14
|
-
|
|
15
|
-
@action_defaults = Trait.new &ResourceDefinition.generate_defaults_block
|
|
16
|
-
|
|
17
|
-
@version_options = {}
|
|
18
|
-
@metadata = {}
|
|
19
|
-
@traits = []
|
|
20
|
-
|
|
21
|
-
if self.name
|
|
22
|
-
@prefix = '/' + self.name.split("::").last.underscore
|
|
23
|
-
else
|
|
24
|
-
@prefix = '/'
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
@version_prefix = ''
|
|
28
|
-
|
|
29
|
-
@parent = nil
|
|
30
|
-
@parent_prefix = ''
|
|
31
|
-
|
|
32
|
-
@routing_prefix = nil
|
|
33
|
-
|
|
34
|
-
@on_finalize = Array.new
|
|
35
|
-
|
|
36
|
-
Application.instance.resource_definitions << self
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.generate_defaults_block( version: nil )
|
|
40
|
-
|
|
41
|
-
# Ensure we inherit any base params defined in the API definition for the passed in version
|
|
42
|
-
base_attributes = if (base_params = ApiDefinition.instance.info(version).base_params)
|
|
43
|
-
base_params.attributes
|
|
44
|
-
else
|
|
45
|
-
{}
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
Proc.new do
|
|
49
|
-
unless base_attributes.empty?
|
|
50
|
-
params do
|
|
51
|
-
base_attributes.each do |base_name, base_attribute|
|
|
52
|
-
attribute base_name, base_attribute.type, **base_attribute.options
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.finalize!
|
|
60
|
-
Application.instance.resource_definitions.each do |resource_definition|
|
|
61
|
-
while (block = resource_definition.on_finalize.shift)
|
|
62
|
-
block.call
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
module ClassMethods
|
|
70
|
-
attr_reader :actions
|
|
71
|
-
attr_reader :responses
|
|
72
|
-
attr_reader :version_options
|
|
73
|
-
attr_reader :traits
|
|
74
|
-
attr_reader :version_prefix
|
|
75
|
-
attr_reader :parent_prefix
|
|
76
|
-
|
|
77
|
-
# opaque hash of user-defined medata, used to decorate the definition,
|
|
78
|
-
# and also available in the generated JSON documents
|
|
79
|
-
attr_reader :metadata
|
|
80
|
-
|
|
81
|
-
attr_accessor :controller
|
|
82
|
-
|
|
83
|
-
def display_name( string=nil )
|
|
84
|
-
unless string
|
|
85
|
-
return @display_name ||= self.name.split("::").last # Best guess at a display name?
|
|
86
|
-
end
|
|
87
|
-
@display_name = string
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def on_finalize(&block)
|
|
91
|
-
if block_given?
|
|
92
|
-
@on_finalize << proc(&block)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
@on_finalize
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def prefix(prefix=nil)
|
|
99
|
-
return @prefix if prefix.nil?
|
|
100
|
-
@routing_prefix = nil # reset routing_prefix
|
|
101
|
-
@prefix = prefix
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def media_type(media_type=nil)
|
|
105
|
-
return @media_type if media_type.nil?
|
|
106
|
-
|
|
107
|
-
if media_type.kind_of?(String)
|
|
108
|
-
media_type = SimpleMediaType.new(media_type)
|
|
109
|
-
end
|
|
110
|
-
@media_type = media_type
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def parent(parent=nil, **mapping)
|
|
115
|
-
return @parent if parent.nil?
|
|
116
|
-
|
|
117
|
-
@routing_prefix = nil # reset routing_prefix
|
|
118
|
-
|
|
119
|
-
parent_action = parent.canonical_path
|
|
120
|
-
parent_route = parent_action.route.path
|
|
121
|
-
|
|
122
|
-
# if a mapping is passed, it *must* resolve any param name conflicts
|
|
123
|
-
unless mapping.any?
|
|
124
|
-
# assume last capture is the relevant one to replace
|
|
125
|
-
# if not... then I quit.
|
|
126
|
-
parent_param_name = parent_route.names.last
|
|
127
|
-
|
|
128
|
-
# more assumptions about names
|
|
129
|
-
parent_name = parent.name.demodulize.underscore.singularize
|
|
130
|
-
|
|
131
|
-
# put it together to find what we should call this new param
|
|
132
|
-
param = "#{parent_name}_#{parent_param_name}".to_sym
|
|
133
|
-
mapping[parent_param_name.to_sym] = param
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# complete the mapping and massage the route
|
|
137
|
-
parent_route.names.collect(&:to_sym).each do |name|
|
|
138
|
-
if mapping.key?(name)
|
|
139
|
-
param = mapping[name]
|
|
140
|
-
# FIXME: this won't handle URI Template type paths, ie '/{parent_id}'
|
|
141
|
-
prefixed_path = parent_action.route.prefixed_path
|
|
142
|
-
@parent_prefix = prefixed_path.gsub(/(:)(#{name})(\W+|$)/, "\\1#{param.to_s}\\3")
|
|
143
|
-
else
|
|
144
|
-
mapping[name] = name
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
self.on_finalize do
|
|
149
|
-
self.inherit_params_from_parent(parent_action, **mapping)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
@parent = parent
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def inherit_params_from_parent(parent_action, **mapping)
|
|
156
|
-
actions.each do |name, action|
|
|
157
|
-
action.params do
|
|
158
|
-
mapping.each do |parent_name, name|
|
|
159
|
-
next if action.params && action.params.attributes.key?(name)
|
|
160
|
-
|
|
161
|
-
parent_attribute = parent_action.params.attributes[parent_name]
|
|
162
|
-
|
|
163
|
-
attribute name, parent_attribute.type, **parent_attribute.options
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
attr_writer :routing_prefix
|
|
171
|
-
|
|
172
|
-
def routing_prefix
|
|
173
|
-
return @routing_prefix if @routing_prefix
|
|
174
|
-
|
|
175
|
-
@routing_prefix = parent_prefix + prefix
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
def version(version=nil, options=nil)
|
|
180
|
-
return @version unless version
|
|
181
|
-
|
|
182
|
-
@version = version
|
|
183
|
-
|
|
184
|
-
unless options.nil?
|
|
185
|
-
warn 'DEPRECATED: ResourceDefinition.version with options is no longer supported. Define in api global info instead.'
|
|
186
|
-
|
|
187
|
-
@version_options = options
|
|
188
|
-
version_using = Array(@version_options[:using])
|
|
189
|
-
if version_using.include?(:path)
|
|
190
|
-
@version_prefix = "#{Praxis::Request::path_version_prefix}#{self.version}"
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
@action_defaults.instance_eval &ResourceDefinition.generate_defaults_block( version: version )
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
def canonical_path(action_name=nil)
|
|
199
|
-
if action_name
|
|
200
|
-
raise "Canonical path for #{self.name} is already defined as: '#{@canonical_action_name}'. 'canonical_path' can only be defined once." if @canonical_action_name
|
|
201
|
-
@canonical_action_name = action_name
|
|
202
|
-
else
|
|
203
|
-
# Resolution of the actual action definition needs to be done lazily, since we can use the `canonical_path` stanza
|
|
204
|
-
# at the top of the resource, well before the actual action is defined.
|
|
205
|
-
unless @canonical_action
|
|
206
|
-
href_action = @canonical_action_name || DEFAULT_RESOURCE_HREF_ACTION
|
|
207
|
-
@canonical_action = actions.fetch(href_action) do
|
|
208
|
-
raise "Error: trying to set canonical_href of #{self.name}. Action '#{href_action}' does not exist"
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
return @canonical_action
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def to_href( params )
|
|
216
|
-
canonical_path.route.path.expand(params)
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def parse_href(path)
|
|
220
|
-
if path.kind_of?(::URI::Generic)
|
|
221
|
-
path = path.path
|
|
222
|
-
end
|
|
223
|
-
param_values = canonical_path.route.path.params(path)
|
|
224
|
-
attrs = canonical_path.params.attributes
|
|
225
|
-
param_values.each_with_object({}) do |(key,value),hash|
|
|
226
|
-
hash[key.to_sym] = attrs[key.to_sym].load(value,[key])
|
|
227
|
-
end
|
|
228
|
-
rescue => e
|
|
229
|
-
raise Praxis::Exception.new("Error parsing or coercing parameters from href: #{path}\n"+e.message)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def trait(trait_name)
|
|
233
|
-
unless ApiDefinition.instance.traits.has_key? trait_name
|
|
234
|
-
raise Exceptions::InvalidTrait.new("Trait #{trait_name} not found in the system")
|
|
235
|
-
end
|
|
236
|
-
trait = ApiDefinition.instance.traits.fetch(trait_name)
|
|
237
|
-
@traits << trait_name
|
|
238
|
-
end
|
|
239
|
-
alias_method :use, :trait
|
|
240
|
-
|
|
241
|
-
def action_defaults(&block)
|
|
242
|
-
if block_given?
|
|
243
|
-
@action_defaults.instance_eval(&block)
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
@action_defaults
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def params(type=Attributor::Struct, **opts, &block)
|
|
250
|
-
warn 'DEPRECATED: ResourceDefinition.params is deprecated. Use it in action_defaults instead.'
|
|
251
|
-
action_defaults do
|
|
252
|
-
params type, **opts, &block
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def payload(type=Attributor::Struct, **opts, &block)
|
|
257
|
-
warn 'DEPRECATED: ResourceDefinition.payload is deprecated. Use action_defaults instead.'
|
|
258
|
-
action_defaults do
|
|
259
|
-
payload type, **opts, &block
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def headers(**opts, &block)
|
|
264
|
-
warn 'DEPRECATED: ResourceDefinition.headers is deprecated. Use action_defaults instead.'
|
|
265
|
-
action_defaults do
|
|
266
|
-
headers **opts, &block
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def response(name, **args)
|
|
271
|
-
warn 'DEPRECATED: ResourceDefinition.response is deprecated. Use action_defaults instead.'
|
|
272
|
-
action_defaults do
|
|
273
|
-
response name, **args
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
def action(name, &block)
|
|
278
|
-
raise ArgumentError, "can not create ActionDefinition without block" unless block_given?
|
|
279
|
-
raise ArgumentError, "Action names must be defined using symbols (Got: #{name} (of type #{name.class}))" unless name.is_a? Symbol
|
|
280
|
-
@actions[name] = ActionDefinition.new(name, self, &block)
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def description(text=nil)
|
|
284
|
-
@description = text if text
|
|
285
|
-
@description
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def id
|
|
289
|
-
self.name.gsub('::'.freeze,'-'.freeze)
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
def describe(context: nil)
|
|
293
|
-
{}.tap do |hash|
|
|
294
|
-
hash[:description] = description
|
|
295
|
-
hash[:media_type] = media_type.describe(true) if media_type
|
|
296
|
-
hash[:actions] = actions.values.collect{|action| action.describe(context: context)}
|
|
297
|
-
hash[:name] = self.name
|
|
298
|
-
hash[:parent] = self.parent.id if self.parent
|
|
299
|
-
hash[:display_name] = self.display_name
|
|
300
|
-
hash[:metadata] = metadata
|
|
301
|
-
hash[:traits] = self.traits
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def nodoc!
|
|
306
|
-
metadata[:doc_visibility] = :none
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
end
|
|
312
|
-
end
|
|
2
|
+
raise "ResourceDefinition class has changed name in this version of Praxis.\n" \
|
|
3
|
+
'Please blanket-replace all uses of ResourceDefinition with EndpointDefinition instead.'
|
|
@@ -311,16 +311,8 @@ module Praxis
|
|
|
311
311
|
def validate_parts!(response)
|
|
312
312
|
return unless parts
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
response.body.each do |part|
|
|
317
|
-
parts.validate(part)
|
|
318
|
-
end
|
|
319
|
-
else
|
|
320
|
-
# TODO: remove with other Multipart deprecations.
|
|
321
|
-
response.parts.each do |name, part|
|
|
322
|
-
parts.validate(part)
|
|
323
|
-
end
|
|
314
|
+
response.body.each do |part|
|
|
315
|
+
parts.validate(part)
|
|
324
316
|
end
|
|
325
317
|
end
|
|
326
318
|
|
|
@@ -9,15 +9,15 @@ module Praxis
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def compile(action=nil, **args)
|
|
12
|
-
# Default media_type to the
|
|
12
|
+
# Default media_type to the endpoint_definition one, if the block has it in
|
|
13
13
|
# its required args but no value is passed (funky, but can help in the common case)
|
|
14
14
|
if block.parameters.any? { |(type, name)| name == :media_type && type == :keyreq } && action
|
|
15
15
|
unless args.has_key? :media_type
|
|
16
|
-
media_type = action.
|
|
16
|
+
media_type = action.endpoint_definition.media_type
|
|
17
17
|
unless media_type
|
|
18
18
|
raise Exceptions::InvalidConfiguration.new(
|
|
19
19
|
"Could not default :media_type argument for response template #{@name}." +
|
|
20
|
-
"
|
|
20
|
+
" Endpoint #{action.endpoint_definition} does not have an associated mediatype and none was passed"
|
|
21
21
|
)
|
|
22
22
|
end
|
|
23
23
|
args[:media_type] = media_type
|
data/lib/praxis/router.rb
CHANGED
|
@@ -52,8 +52,8 @@ module Praxis
|
|
|
52
52
|
def add_route(target, route)
|
|
53
53
|
path_versioning = (Application.instance.versioning_scheme == :path)
|
|
54
54
|
|
|
55
|
-
# DEPRECATED: remove with
|
|
56
|
-
path_versioning ||= (target.action.
|
|
55
|
+
# DEPRECATED: remove with EndpointDefinition.version using: :path
|
|
56
|
+
path_versioning ||= (target.action.endpoint_definition.version_options[:using] == :path)
|
|
57
57
|
|
|
58
58
|
unless path_versioning
|
|
59
59
|
target = VersionMatcher.new(target, version: route.version)
|
|
@@ -53,7 +53,7 @@ module Praxis
|
|
|
53
53
|
end
|
|
54
54
|
prefixed_path = path.gsub('//','/')
|
|
55
55
|
path = (base + path).gsub('//','/')
|
|
56
|
-
pattern = Mustermann.new(path, {ignore_unknown_options: true}.merge( options ))
|
|
56
|
+
pattern = Mustermann.new(path, **{ignore_unknown_options: true}.merge( options ))
|
|
57
57
|
@route = Route.new(verb, pattern, version, prefixed_path: prefixed_path, **options)
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -2,68 +2,8 @@ namespace :praxis do
|
|
|
2
2
|
|
|
3
3
|
namespace :docs do
|
|
4
4
|
|
|
5
|
-
def base_path
|
|
6
|
-
require 'uri'
|
|
7
|
-
documentation_url = Praxis::ApiDefinition.instance.global_info.documentation_url
|
|
8
|
-
URI(documentation_url).path.gsub(/\/[^\/]*$/, '/') if documentation_url
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
path = File.expand_path(File.join(File.dirname(__FILE__), '../../api_browser'))
|
|
12
|
-
|
|
13
|
-
desc "Install dependencies"
|
|
14
|
-
task :install do
|
|
15
|
-
unless system("npm install --production", chdir: path)
|
|
16
|
-
raise Exception.new("NPM Install Failed")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
docs_dir = File.join(Dir.pwd, 'docs')
|
|
20
|
-
FileUtils.mkdir_p docs_dir unless File.directory? docs_dir
|
|
21
|
-
|
|
22
|
-
# The doc browser will need to have a minimal app.js and styles.css file at the root
|
|
23
|
-
# Let's add them if the app has not overriden them
|
|
24
|
-
js_file = File.join(Dir.pwd, 'docs', 'app.js')
|
|
25
|
-
scss_file = File.join(Dir.pwd, 'docs', 'styles.scss')
|
|
26
|
-
template_directory = File.expand_path(File.join(File.dirname(__FILE__), '../../../tasks/thor/templates/generator/empty_app/docs'))
|
|
27
|
-
|
|
28
|
-
unless File.exists? js_file
|
|
29
|
-
FileUtils.cp File.join(template_directory, 'app.js'), js_file
|
|
30
|
-
end
|
|
31
|
-
unless File.exists? scss_file
|
|
32
|
-
FileUtils.cp File.join(template_directory, 'styles.scss'), scss_file
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
desc "Run API Documentation Browser"
|
|
37
|
-
task :preview, [:port] => [:install, :generate] do |t, args|
|
|
38
|
-
doc_port = args[:port] || '9090'
|
|
39
|
-
exec({
|
|
40
|
-
'USER_DOCS_PATH' => File.join(Dir.pwd, 'docs'),
|
|
41
|
-
'DOC_PORT' => doc_port,
|
|
42
|
-
'PLUGIN_PATHS' => Praxis::Application.instance.doc_browser_plugin_paths.join(':'),
|
|
43
|
-
'BASE_PATH' => '/'
|
|
44
|
-
}, "#{path}/node_modules/.bin/grunt serve --gruntfile '#{path}/Gruntfile.js'")
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
desc "Build docs that can be shipped"
|
|
48
|
-
task :build => [:install, :generate] do
|
|
49
|
-
exec({
|
|
50
|
-
'USER_DOCS_PATH' => File.join(Dir.pwd, 'docs'),
|
|
51
|
-
'PLUGIN_PATHS' => Praxis::Application.instance.doc_browser_plugin_paths.join(':'),
|
|
52
|
-
'BASE_PATH' => base_path
|
|
53
|
-
}, "#{path}/node_modules/.bin/grunt build --gruntfile '#{path}/Gruntfile.js'")
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
desc "Generate API docs (JSON definitions) for a Praxis App"
|
|
57
|
-
task :generate => [:environment] do |t, args|
|
|
58
|
-
require 'fileutils'
|
|
59
|
-
|
|
60
|
-
Praxis::Blueprint.caching_enabled = false
|
|
61
|
-
generator = Praxis::Docs::Generator.new(Dir.pwd)
|
|
62
|
-
generator.save!
|
|
63
|
-
end
|
|
64
|
-
|
|
65
5
|
desc "Generate OpenAPI 3 docs for a Praxis App"
|
|
66
|
-
task :
|
|
6
|
+
task :generate => [:environment] do |t, args|
|
|
67
7
|
require 'fileutils'
|
|
68
8
|
|
|
69
9
|
Praxis::Blueprint.caching_enabled = false
|
|
@@ -72,7 +12,7 @@ namespace :praxis do
|
|
|
72
12
|
end
|
|
73
13
|
|
|
74
14
|
desc "Preview (and Generate) OpenAPI 3 docs for a Praxis App"
|
|
75
|
-
task :
|
|
15
|
+
task :preview => [:generate] do |t, args|
|
|
76
16
|
require 'webrick'
|
|
77
17
|
docs_port = 9090
|
|
78
18
|
root = Dir.pwd + '/docs/openapi/'
|
|
@@ -81,9 +21,22 @@ namespace :praxis do
|
|
|
81
21
|
trap('INT') { s.shutdown }
|
|
82
22
|
s.start
|
|
83
23
|
end
|
|
84
|
-
|
|
24
|
+
# If there is only 1 version we'll feature it and open the browser onto it
|
|
25
|
+
versions = Dir.children(root)
|
|
26
|
+
featured_version = (versions.size < 2) ? "#{versions.first}/" : ''
|
|
27
|
+
`open http://localhost:#{docs_port}/#{featured_version}`
|
|
85
28
|
wb.join
|
|
86
29
|
end
|
|
87
|
-
|
|
30
|
+
desc "Generate and package all OpenApi Docs into a zip, ready for a Web server (like S3...) to present it"
|
|
31
|
+
task :package => [:generate] do |t, args|
|
|
32
|
+
docs_root = Dir.pwd + '/docs/openapi/'
|
|
33
|
+
zip_file = Dir.pwd + '/docs/openapi.zip'
|
|
34
|
+
`rm -f #{zip_file}`
|
|
35
|
+
# NOTE: This assumes the "zip" utility is installed, supporting the recursive flag.
|
|
36
|
+
`zip -r #{zip_file} #{docs_root}`
|
|
37
|
+
puts
|
|
38
|
+
puts "Left packaged API docs in #{zip_file}"
|
|
39
|
+
puts " --> To view the docs, unzip the file under a web server (or S3...) and access the index.hml files from a browser"
|
|
40
|
+
end
|
|
88
41
|
end
|
|
89
42
|
end
|