praxis 0.22.pre.2 → 2.0.pre.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +5 -20
- data/CHANGELOG.md +333 -324
- data/lib/praxis.rb +14 -9
- data/lib/praxis/action_definition.rb +8 -10
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
- data/lib/praxis/api_definition.rb +27 -44
- data/lib/praxis/api_general_info.rb +23 -3
- data/lib/praxis/application.rb +15 -142
- data/lib/praxis/bootloader.rb +1 -2
- data/lib/praxis/bootloader_stages/environment.rb +13 -0
- data/lib/praxis/config.rb +1 -1
- data/lib/praxis/controller.rb +0 -2
- data/lib/praxis/dispatcher.rb +4 -6
- data/lib/praxis/docs/generator.rb +19 -24
- data/lib/praxis/docs/link_builder.rb +1 -1
- data/lib/praxis/docs/open_api_generator.rb +255 -0
- data/lib/praxis/docs/openapi/info_object.rb +31 -0
- data/lib/praxis/docs/openapi/media_type_object.rb +59 -0
- data/lib/praxis/docs/openapi/operation_object.rb +40 -0
- data/lib/praxis/docs/openapi/parameter_object.rb +69 -0
- data/lib/praxis/docs/openapi/paths_object.rb +58 -0
- data/lib/praxis/docs/openapi/request_body_object.rb +51 -0
- data/lib/praxis/docs/openapi/response_object.rb +63 -0
- data/lib/praxis/docs/openapi/responses_object.rb +44 -0
- data/lib/praxis/docs/openapi/schema_object.rb +87 -0
- data/lib/praxis/docs/openapi/server_object.rb +24 -0
- data/lib/praxis/docs/openapi/tag_object.rb +21 -0
- data/lib/praxis/error_handler.rb +5 -5
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +1 -1
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +4 -0
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
- data/lib/praxis/extensions/field_selection.rb +1 -12
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +28 -34
- data/lib/praxis/extensions/field_selection/field_selector.rb +4 -0
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +35 -39
- data/lib/praxis/extensions/rendering.rb +1 -1
- data/lib/praxis/file_group.rb +1 -1
- data/lib/praxis/handlers/xml.rb +1 -1
- data/lib/praxis/links.rb +4 -0
- data/lib/praxis/mapper/active_model_compat.rb +98 -0
- data/lib/praxis/mapper/resource.rb +242 -0
- data/lib/praxis/mapper/selector_generator.rb +150 -0
- data/lib/praxis/mapper/sequel_compat.rb +76 -0
- data/lib/praxis/media_type_identifier.rb +2 -1
- data/lib/praxis/middleware_app.rb +13 -15
- data/lib/praxis/multipart/part.rb +8 -7
- data/lib/praxis/notifications.rb +1 -1
- data/lib/praxis/plugins/mapper_plugin.rb +64 -0
- data/lib/praxis/request.rb +14 -7
- data/lib/praxis/request_stages/response.rb +2 -3
- data/lib/praxis/resource_definition.rb +15 -19
- data/lib/praxis/response.rb +6 -5
- data/lib/praxis/response_definition.rb +6 -8
- data/lib/praxis/response_template.rb +3 -4
- data/lib/praxis/responses/http.rb +36 -0
- data/lib/praxis/responses/internal_server_error.rb +12 -3
- data/lib/praxis/responses/multipart_ok.rb +11 -4
- data/lib/praxis/responses/validation_error.rb +10 -1
- data/lib/praxis/route.rb +1 -1
- data/lib/praxis/router.rb +3 -3
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/tasks/api_docs.rb +24 -9
- data/lib/praxis/tasks/routes.rb +0 -1
- data/lib/praxis/trait.rb +1 -1
- data/lib/praxis/types/media_type_common.rb +12 -2
- data/lib/praxis/types/multipart.rb +1 -1
- data/lib/praxis/types/multipart_array.rb +64 -2
- data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +11 -9
- data/spec/functional_spec.rb +0 -1
- data/spec/praxis/action_definition_spec.rb +16 -27
- data/spec/praxis/api_definition_spec.rb +8 -13
- data/spec/praxis/api_general_info_spec.rb +8 -3
- data/spec/praxis/application_spec.rb +8 -14
- data/spec/praxis/collection_spec.rb +3 -2
- data/spec/praxis/config_spec.rb +2 -2
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +106 -0
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +147 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_active_model.rb +130 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_sequel.rb +106 -0
- data/spec/praxis/handlers/xml_spec.rb +2 -2
- data/spec/praxis/mapper/resource_spec.rb +169 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +325 -0
- data/spec/praxis/media_type_spec.rb +0 -10
- data/spec/praxis/middleware_app_spec.rb +16 -10
- data/spec/praxis/request_spec.rb +7 -17
- data/spec/praxis/request_stages/action_spec.rb +8 -1
- data/spec/praxis/request_stages/validate_spec.rb +1 -1
- data/spec/praxis/resource_definition_spec.rb +10 -12
- data/spec/praxis/response_definition_spec.rb +19 -30
- data/spec/praxis/response_spec.rb +6 -13
- data/spec/praxis/responses/internal_server_error_spec.rb +5 -2
- data/spec/praxis/router_spec.rb +5 -9
- data/spec/spec_app/app/controllers/instances.rb +1 -1
- data/spec/spec_app/config.ru +6 -1
- data/spec/spec_app/config/environment.rb +3 -21
- data/spec/spec_app/design/api.rb +6 -0
- data/spec/spec_helper.rb +13 -17
- data/spec/support/be_deep_equal_matcher.rb +39 -0
- data/spec/support/spec_resources.rb +124 -0
- metadata +86 -53
- data/lib/praxis/extensions/attribute_filtering.rb +0 -28
- data/lib/praxis/extensions/attribute_filtering/query_builder.rb +0 -39
- data/lib/praxis/extensions/mapper_selectors.rb +0 -16
- data/lib/praxis/media_type_collection.rb +0 -127
- data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
- data/spec/praxis/media_type_collection_spec.rb +0 -157
- data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
- data/spec/spec_app/app/models/person.rb +0 -3
data/lib/praxis.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'rack'
|
2
2
|
require 'attributor'
|
3
|
-
require 'praxis-mapper'
|
4
3
|
require 'praxis-blueprints'
|
5
4
|
|
6
5
|
require 'active_support/concern'
|
7
6
|
require 'praxis/request_superclassing'
|
7
|
+
require 'active_support/inflector'
|
8
8
|
|
9
9
|
$:.unshift File.dirname(__FILE__)
|
10
10
|
|
@@ -51,6 +51,7 @@ module Praxis
|
|
51
51
|
module Docs
|
52
52
|
autoload :Generator, 'praxis/docs/generator'
|
53
53
|
autoload :LinkBuilder, 'praxis/docs/link_builder'
|
54
|
+
autoload :OpenApiGenerator, 'praxis/docs/open_api_generator'
|
54
55
|
end
|
55
56
|
|
56
57
|
# types
|
@@ -62,7 +63,6 @@ module Praxis
|
|
62
63
|
|
63
64
|
autoload :Links, 'praxis/links'
|
64
65
|
autoload :MediaType, 'praxis/media_type'
|
65
|
-
autoload :MediaTypeCollection, 'praxis/media_type_collection'
|
66
66
|
autoload :MediaTypeIdentifier, 'praxis/media_type_identifier'
|
67
67
|
autoload :Multipart, 'praxis/types/multipart'
|
68
68
|
autoload :Collection, 'praxis/collection'
|
@@ -89,7 +89,8 @@ module Praxis
|
|
89
89
|
autoload :MapperSelectors, 'praxis/extensions/mapper_selectors'
|
90
90
|
autoload :Rendering, 'praxis/extensions/rendering'
|
91
91
|
autoload :FieldExpansion, 'praxis/extensions/field_expansion'
|
92
|
-
autoload :
|
92
|
+
autoload :ActiveRecordFilterQueryBuilder, 'praxis/extensions/attribute_filtering/active_record_filter_query_builder'
|
93
|
+
autoload :SequelFilterQueryBuilder, 'praxis/extensions/attribute_filtering/sequel_filter_query_builder'
|
93
94
|
end
|
94
95
|
|
95
96
|
module Handlers
|
@@ -123,11 +124,15 @@ module Praxis
|
|
123
124
|
autoload :Response, 'praxis/request_stages/response'
|
124
125
|
end
|
125
126
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
#
|
127
|
+
module Mapper
|
128
|
+
autoload :Resource, 'praxis/mapper/resource'
|
129
|
+
autoload :SelectorGenerator, 'praxis/mapper/selector_generator'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Avoid loading responses (and templates) lazily as they need to be registered in time
|
133
|
+
require 'praxis/responses/http'
|
134
|
+
require 'praxis/responses/internal_server_error'
|
135
|
+
require 'praxis/responses/validation_error'
|
136
|
+
require 'praxis/responses/multipart_ok'
|
132
137
|
|
133
138
|
end
|
@@ -12,7 +12,6 @@ module Praxis
|
|
12
12
|
|
13
13
|
attr_reader :name
|
14
14
|
attr_reader :resource_definition
|
15
|
-
attr_reader :api_definition
|
16
15
|
attr_reader :routes
|
17
16
|
attr_reader :primary_route
|
18
17
|
attr_reader :named_routes
|
@@ -40,7 +39,6 @@ module Praxis
|
|
40
39
|
@metadata = Hash.new
|
41
40
|
@routes = []
|
42
41
|
@traits = []
|
43
|
-
@api_definition = resource_definition.application.api_definition
|
44
42
|
|
45
43
|
if (media_type = resource_definition.media_type)
|
46
44
|
if media_type.kind_of?(Class) && media_type < Praxis::Types::MediaTypeCommon
|
@@ -49,7 +47,7 @@ module Praxis
|
|
49
47
|
end
|
50
48
|
|
51
49
|
version = resource_definition.version
|
52
|
-
api_info =
|
50
|
+
api_info = ApiDefinition.instance.info(resource_definition.version)
|
53
51
|
|
54
52
|
route_base = "#{api_info.base_path}#{resource_definition.version_prefix}"
|
55
53
|
prefix = Array(resource_definition.routing_prefix)
|
@@ -66,11 +64,11 @@ module Praxis
|
|
66
64
|
end
|
67
65
|
|
68
66
|
def trait(trait_name)
|
69
|
-
unless
|
67
|
+
unless ApiDefinition.instance.traits.has_key? trait_name
|
70
68
|
raise Exceptions::InvalidTrait.new("Trait #{trait_name} not found in the system")
|
71
69
|
end
|
72
70
|
|
73
|
-
trait =
|
71
|
+
trait = ApiDefinition.instance.traits.fetch(trait_name)
|
74
72
|
trait.apply!(self)
|
75
73
|
traits << trait_name
|
76
74
|
end
|
@@ -78,7 +76,7 @@ module Praxis
|
|
78
76
|
|
79
77
|
def update_attribute(attribute, options, block)
|
80
78
|
attribute.options.merge!(options)
|
81
|
-
attribute.type.attributes(options, &block)
|
79
|
+
attribute.type.attributes(**options, &block)
|
82
80
|
end
|
83
81
|
|
84
82
|
def response(name, type=nil, **args, &block)
|
@@ -92,7 +90,7 @@ module Praxis
|
|
92
90
|
args[:media_type] = type
|
93
91
|
end
|
94
92
|
|
95
|
-
template =
|
93
|
+
template = ApiDefinition.instance.response(name)
|
96
94
|
@responses[name] = template.compile(self, **args)
|
97
95
|
end
|
98
96
|
|
@@ -305,7 +303,7 @@ module Praxis
|
|
305
303
|
|
306
304
|
# and return that one if it already corresponds to a registered handler
|
307
305
|
# otherwise, add the encoding
|
308
|
-
if
|
306
|
+
if Praxis::Application.instance.handlers.include?(pick.handler_name)
|
309
307
|
return pick
|
310
308
|
else
|
311
309
|
return pick + handler_name
|
@@ -322,13 +320,13 @@ module Praxis
|
|
322
320
|
|
323
321
|
hash[:examples] = {}
|
324
322
|
|
325
|
-
default_handlers =
|
323
|
+
default_handlers = ApiDefinition.instance.info.consumes
|
326
324
|
|
327
325
|
default_handlers.each do |default_handler|
|
328
326
|
dumped_payload = payload.dump(example, default_format: default_handler)
|
329
327
|
|
330
328
|
content_type = derive_content_type(example, default_handler)
|
331
|
-
handler =
|
329
|
+
handler = Praxis::Application.instance.handlers[content_type.handler_name]
|
332
330
|
|
333
331
|
# in case handler is nil, use dumped_payload as-is.
|
334
332
|
generated_payload = if handler.nil?
|
@@ -25,7 +25,7 @@ module Praxis
|
|
25
25
|
# Defining the existence without any other options can only mean that it is required (otherwise it is a useless definition)
|
26
26
|
options[:required] = true if options.empty?
|
27
27
|
end
|
28
|
-
key name , String, options
|
28
|
+
key name , String, **options
|
29
29
|
end
|
30
30
|
|
31
31
|
# Override the attribute to really call "key" in the hash (for temporary backwards compat)
|
@@ -1,57 +1,41 @@
|
|
1
|
+
require 'singleton'
|
1
2
|
require 'forwardable'
|
2
3
|
|
3
4
|
module Praxis
|
4
5
|
|
5
6
|
class ApiDefinition
|
7
|
+
include Singleton
|
6
8
|
extend Forwardable
|
7
9
|
|
8
10
|
attr_reader :traits
|
9
11
|
attr_reader :responses
|
10
12
|
attr_reader :infos
|
11
13
|
attr_reader :global_info
|
12
|
-
attr_reader :application
|
13
14
|
|
14
15
|
attr_accessor :versioning_scheme
|
15
16
|
|
16
|
-
def self.instance
|
17
|
-
i = Thread.current[:praxis_instance] || $praxis_initializing_instance
|
18
|
-
raise "Trying to use Praxis::ApiDefinition outside the context of a Praxis::Application" unless i
|
19
|
-
i.api_definition
|
20
|
-
end
|
21
|
-
|
22
17
|
def self.define(&block)
|
23
|
-
|
24
|
-
definition = Praxis::Application.current_instance.api_definition
|
25
|
-
if block.arity == 0
|
26
|
-
definition.instance_eval(&block)
|
27
|
-
else
|
28
|
-
yield(definition)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def define(&block)
|
33
18
|
if block.arity == 0
|
34
|
-
self.instance_eval(&block)
|
19
|
+
self.instance.instance_eval(&block)
|
35
20
|
else
|
36
|
-
yield(self)
|
21
|
+
yield(self.instance)
|
37
22
|
end
|
38
23
|
end
|
39
24
|
|
40
|
-
def initialize
|
41
|
-
@application = application
|
25
|
+
def initialize
|
42
26
|
@responses = Hash.new
|
43
27
|
@traits = Hash.new
|
44
28
|
@base_path = ''
|
45
29
|
|
46
|
-
@global_info = ApiGeneralInfo.new
|
30
|
+
@global_info = ApiGeneralInfo.new
|
47
31
|
|
48
32
|
@infos = Hash.new do |hash, version|
|
49
|
-
hash[version] = ApiGeneralInfo.new(@global_info,
|
33
|
+
hash[version] = ApiGeneralInfo.new(@global_info, version: version)
|
50
34
|
end
|
51
35
|
end
|
52
36
|
|
53
37
|
def response_template(name, &block)
|
54
|
-
@responses[name] = Praxis::ResponseTemplate.new(name,
|
38
|
+
@responses[name] = Praxis::ResponseTemplate.new(name, &block)
|
55
39
|
end
|
56
40
|
|
57
41
|
def response(name)
|
@@ -107,26 +91,25 @@ module Praxis
|
|
107
91
|
data
|
108
92
|
end
|
109
93
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# end
|
94
|
+
define do |api|
|
95
|
+
api.response_template :ok do |media_type: , location: nil, headers: nil, description: nil |
|
96
|
+
status 200
|
97
|
+
description( description || 'Standard response for successful HTTP requests.' )
|
98
|
+
|
99
|
+
media_type media_type
|
100
|
+
location location
|
101
|
+
headers headers if headers
|
102
|
+
end
|
103
|
+
|
104
|
+
api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
|
105
|
+
status 201
|
106
|
+
description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
|
107
|
+
|
108
|
+
media_type media_type if media_type
|
109
|
+
location location
|
110
|
+
headers headers if headers
|
111
|
+
end
|
112
|
+
end
|
130
113
|
|
131
114
|
end
|
132
115
|
|
@@ -3,11 +3,10 @@ module Praxis
|
|
3
3
|
|
4
4
|
attr_reader :version
|
5
5
|
|
6
|
-
def initialize(global_info=nil,
|
6
|
+
def initialize(global_info=nil, version: nil)
|
7
7
|
@data = Hash.new
|
8
8
|
@global_info = global_info
|
9
9
|
@version = version
|
10
|
-
@application = application
|
11
10
|
|
12
11
|
if @global_info.nil? # this *is* the global info
|
13
12
|
version_with [:header, :params]
|
@@ -16,6 +15,19 @@ module Praxis
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
18
|
+
# Allow any custom method to get/set any value
|
19
|
+
def method_missing(name, val=nil)
|
20
|
+
if val.nil?
|
21
|
+
get(name)
|
22
|
+
else
|
23
|
+
set(name, val)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_to_missing?(*)
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
19
31
|
def get(k)
|
20
32
|
return @data[k] if @data.key?(k)
|
21
33
|
return @global_info.get(k) if @global_info
|
@@ -42,6 +54,14 @@ module Praxis
|
|
42
54
|
end
|
43
55
|
end
|
44
56
|
|
57
|
+
def logo_url(val=nil)
|
58
|
+
if val.nil?
|
59
|
+
get(:logo_url)
|
60
|
+
else
|
61
|
+
set(:logo_url, val)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
45
65
|
def description(val=nil)
|
46
66
|
if val.nil?
|
47
67
|
get(:description)
|
@@ -55,7 +75,7 @@ module Praxis
|
|
55
75
|
get(:version_with)
|
56
76
|
else
|
57
77
|
if @global_info.nil? # this *is* the global info
|
58
|
-
|
78
|
+
Application.instance.versioning_scheme = val
|
59
79
|
set(:version_with, val)
|
60
80
|
else
|
61
81
|
raise "Use of version_with is only allowed in the global part of " \
|
data/lib/praxis/application.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
require 'singleton'
|
1
2
|
require 'mustermann'
|
2
3
|
require 'logger'
|
3
4
|
|
4
5
|
module Praxis
|
5
6
|
class Application
|
7
|
+
include Singleton
|
6
8
|
|
7
9
|
attr_reader :router
|
8
10
|
attr_reader :controllers
|
9
11
|
attr_reader :resource_definitions
|
10
12
|
attr_reader :app
|
11
13
|
attr_reader :builder
|
12
|
-
attr_reader :api_definition
|
13
14
|
|
14
15
|
attr_accessor :bootloader
|
15
16
|
attr_accessor :file_layout
|
@@ -24,30 +25,12 @@ module Praxis
|
|
24
25
|
|
25
26
|
attr_accessor :versioning_scheme
|
26
27
|
|
27
|
-
@@registered_apps = {}
|
28
28
|
|
29
|
-
def self.registered_apps
|
30
|
-
@@registered_apps
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.instance
|
34
|
-
i = current_instance
|
35
|
-
return i if i
|
36
|
-
$praxis_initializing_instance = self.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.current_instance
|
40
|
-
Thread.current[:praxis_instance] || $praxis_initializing_instance
|
41
|
-
end
|
42
|
-
|
43
29
|
def self.configure
|
44
|
-
|
45
|
-
yield(current_instance)
|
30
|
+
yield(self.instance)
|
46
31
|
end
|
47
32
|
|
48
|
-
def initialize
|
49
|
-
old = $praxis_initializing_instance
|
50
|
-
$praxis_initializing_instance = self # ApiDefinition.new needs to get the instance...
|
33
|
+
def initialize
|
51
34
|
@controllers = Set.new
|
52
35
|
@resource_definitions = Set.new
|
53
36
|
|
@@ -68,135 +51,29 @@ module Praxis
|
|
68
51
|
@config = Config.new
|
69
52
|
@root = nil
|
70
53
|
@logger = Logger.new(STDOUT)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
media_type media_type
|
79
|
-
location location
|
80
|
-
headers headers if headers
|
81
|
-
end
|
82
|
-
|
83
|
-
api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
|
84
|
-
status 201
|
85
|
-
description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
|
86
|
-
|
87
|
-
media_type media_type if media_type
|
88
|
-
location location
|
89
|
-
headers headers if headers
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
require 'praxis/responses/http'
|
94
|
-
self.api_definition.define do |api|
|
95
|
-
[
|
96
|
-
[ :accepted, 202, "The request has been accepted for processing, but the processing has not been completed." ],
|
97
|
-
[ :no_content, 204,"The server successfully processed the request, but is not returning any content."],
|
98
|
-
[ :multiple_choices, 300,"Indicates multiple options for the resource that the client may follow."],
|
99
|
-
[ :moved_permanently, 301,"This and all future requests should be directed to the given URI."],
|
100
|
-
[ :found, 302,"The requested resource resides temporarily under a different URI."],
|
101
|
-
[ :see_other, 303,"The response to the request can be found under another URI using a GET method"],
|
102
|
-
[ :not_modified, 304,"Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-Match."],
|
103
|
-
[ :temporary_redirect, 307,"In this case, the request should be repeated with another URI; however, future requests should still use the original URI."],
|
104
|
-
[ :bad_request, 400,"The request cannot be fulfilled due to bad syntax."],
|
105
|
-
[ :unauthorized, 401,"Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided."],
|
106
|
-
[ :forbidden, 403,"The request was a valid request, but the server is refusing to respond to it."],
|
107
|
-
[ :not_found, 404,"The requested resource could not be found but may be available again in the future."],
|
108
|
-
[ :method_not_allowed, 405,"A request was made of a resource using a request method not supported by that resource."],
|
109
|
-
[ :not_acceptable, 406,"The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request."],
|
110
|
-
[ :request_timeout, 408,"The server timed out waiting for the request."],
|
111
|
-
[ :conflict, 409, "Indicates that the request could not be processed because of conflict in the request, such as an edit conflict in the case of multiple updates."],
|
112
|
-
[ :precondition_failed, 412,"The server does not meet one of the preconditions that the requester put on the request."],
|
113
|
-
[ :unprocessable_entity, 422,"The request was well-formed but was unable to be followed due to semantic errors."],
|
114
|
-
].each do |name, code, base_description|
|
115
|
-
api.response_template name do |media_type: nil, location: nil, headers: nil, description: nil|
|
116
|
-
status code
|
117
|
-
description( description || base_description ) # description can "potentially" be overriden in an individual action.
|
118
|
-
|
119
|
-
media_type media_type if media_type
|
120
|
-
location location if location
|
121
|
-
headers headers if headers
|
122
|
-
end
|
123
|
-
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def setup(root: '.')
|
58
|
+
return self unless @app.nil?
|
59
|
+
|
60
|
+
@root = Pathname.new(root).expand_path
|
124
61
|
|
125
|
-
end
|
126
|
-
|
127
|
-
require 'praxis/responses/internal_server_error'
|
128
|
-
self.api_definition.define do |api|
|
129
|
-
api.response_template :internal_server_error do
|
130
|
-
description "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable."
|
131
|
-
status 500
|
132
|
-
media_type "application/json"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
require 'praxis/responses/validation_error'
|
137
|
-
self.api_definition.define do |api|
|
138
|
-
api.response_template :validation_error do
|
139
|
-
description "An error message indicating that one or more elements of the request did not match the API specification for the action"
|
140
|
-
status 400
|
141
|
-
media_type "application/json"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
require 'praxis/responses/multipart_ok'
|
147
|
-
self.api_definition.define do |api|
|
148
|
-
api.response_template :multipart_ok do |media_type: Praxis::Types::MultipartArray|
|
149
|
-
status 200
|
150
|
-
media_type media_type
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
62
|
builtin_handlers = {
|
155
63
|
'plain' => Praxis::Handlers::Plain,
|
156
64
|
'json' => Praxis::Handlers::JSON,
|
157
65
|
'x-www-form-urlencoded' => Praxis::Handlers::WWWForm
|
158
66
|
}
|
159
|
-
|
160
67
|
# Register built-in handlers unless the app already provided its own
|
161
68
|
builtin_handlers.each_pair do |name, handler|
|
162
69
|
self.handler(name, handler) unless handlers.key?(name)
|
163
70
|
end
|
164
|
-
|
165
|
-
setup_initial_config!
|
166
|
-
|
167
|
-
unless skip_registration
|
168
|
-
if self.class.registered_apps[name]
|
169
|
-
raise "A Praxis instance named #{name} has already been registered, please use the :name parameter to initialize them"
|
170
|
-
end
|
171
|
-
self.class.registered_apps[name] = self
|
172
|
-
end
|
173
|
-
$praxis_initializing_instance = old
|
174
|
-
end
|
175
|
-
|
176
|
-
def setup_initial_config!
|
177
|
-
self.config do
|
178
|
-
attribute :praxis do
|
179
|
-
attribute :validate_responses, Attributor::Boolean, default: false
|
180
|
-
attribute :validate_response_bodies, Attributor::Boolean, default: false
|
181
|
-
|
182
|
-
attribute :show_exceptions, Attributor::Boolean, default: false
|
183
|
-
attribute :x_cascade, Attributor::Boolean, default: true
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
71
|
|
189
|
-
|
190
|
-
return self unless @app.nil?
|
191
|
-
saved_value = $praxis_initializing_instance
|
192
|
-
$praxis_initializing_instance = self
|
193
|
-
@root = Pathname.new(root).expand_path
|
72
|
+
@bootloader.setup!
|
194
73
|
|
195
|
-
|
196
|
-
builder.
|
197
|
-
@app = builder.to_app
|
74
|
+
@builder.run(@router)
|
75
|
+
@app = @builder.to_app
|
198
76
|
|
199
|
-
$praxis_initializing_instance = saved_value
|
200
77
|
self
|
201
78
|
end
|
202
79
|
|
@@ -226,13 +103,9 @@ module Praxis
|
|
226
103
|
|
227
104
|
def call(env)
|
228
105
|
response = []
|
229
|
-
old = Thread.current[:praxis_instance]
|
230
|
-
Thread.current[:praxis_instance] = self
|
231
106
|
Notifications.instrument 'rack.request.all'.freeze, response: response do
|
232
107
|
response.push(*@app.call(env))
|
233
108
|
end
|
234
|
-
ensure
|
235
|
-
Thread.current[:praxis_instance] = old
|
236
109
|
end
|
237
110
|
|
238
111
|
def layout(&block)
|
@@ -241,7 +114,7 @@ module Praxis
|
|
241
114
|
|
242
115
|
def config(key=nil, type=Attributor::Struct, **opts, &block)
|
243
116
|
if block_given? || (type==Attributor::Struct && !opts.empty? )
|
244
|
-
@config.define(key, type, opts, &block)
|
117
|
+
@config.define(key, type, **opts, &block)
|
245
118
|
else
|
246
119
|
@config.get
|
247
120
|
end
|