dzl 1.0.0.beta0
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.
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/README.md +44 -0
- data/Rakefile +15 -0
- data/config.ru +41 -0
- data/dzl.gemspec +21 -0
- data/lib/dzl/doc/endpoint_doc.rb +70 -0
- data/lib/dzl/doc/router_doc.rb +26 -0
- data/lib/dzl/doc/task.rb +5 -0
- data/lib/dzl/doc/templates/endpoint.erb +55 -0
- data/lib/dzl/doc/templates/home.erb +8 -0
- data/lib/dzl/doc.rb +58 -0
- data/lib/dzl/dsl_proxies/defaults.rb +10 -0
- data/lib/dzl/dsl_proxies/endpoint.rb +30 -0
- data/lib/dzl/dsl_proxies/parameter.rb +75 -0
- data/lib/dzl/dsl_proxies/parameter_block.rb +61 -0
- data/lib/dzl/dsl_proxies/protection.rb +6 -0
- data/lib/dzl/dsl_proxies/router.rb +62 -0
- data/lib/dzl/dsl_proxy.rb +8 -0
- data/lib/dzl/dsl_subject.rb +15 -0
- data/lib/dzl/dsl_subjects/defaults.rb +12 -0
- data/lib/dzl/dsl_subjects/endpoint.rb +79 -0
- data/lib/dzl/dsl_subjects/parameter/allowed_values.rb +60 -0
- data/lib/dzl/dsl_subjects/parameter/type_conversion.rb +59 -0
- data/lib/dzl/dsl_subjects/parameter.rb +100 -0
- data/lib/dzl/dsl_subjects/parameter_block.rb +64 -0
- data/lib/dzl/dsl_subjects/protection.rb +31 -0
- data/lib/dzl/dsl_subjects/router.rb +87 -0
- data/lib/dzl/errors.rb +33 -0
- data/lib/dzl/examples/base.rb +9 -0
- data/lib/dzl/examples/fun_with_handlers.rb +33 -0
- data/lib/dzl/examples/fun_with_hooks.rb +65 -0
- data/lib/dzl/examples/fun_with_params.rb +71 -0
- data/lib/dzl/examples/fun_with_requests.rb +47 -0
- data/lib/dzl/examples/route_profile.rb +158 -0
- data/lib/dzl/examples/trey.rb +97 -0
- data/lib/dzl/logger.rb +65 -0
- data/lib/dzl/rack_interface.rb +95 -0
- data/lib/dzl/request.rb +54 -0
- data/lib/dzl/response_context/request_helpers.rb +11 -0
- data/lib/dzl/response_context.rb +47 -0
- data/lib/dzl/validator.rb +10 -0
- data/lib/dzl/validators/size.rb +32 -0
- data/lib/dzl/validators/value.rb +30 -0
- data/lib/dzl/value_or_error.rb +32 -0
- data/lib/dzl/version.rb +3 -0
- data/lib/dzl.rb +96 -0
- data/spec/dsl_subject_spec.rb +14 -0
- data/spec/endpoint_doc_spec.rb +25 -0
- data/spec/fun_with_handlers_spec.rb +37 -0
- data/spec/fun_with_hooks_spec.rb +61 -0
- data/spec/fun_with_params_spec.rb +197 -0
- data/spec/fun_with_requests_spec.rb +101 -0
- data/spec/logger_spec.rb +48 -0
- data/spec/route_params_spec.rb +13 -0
- data/spec/router_doc_spec.rb +32 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/trey_spec.rb +135 -0
- data/spec/value_or_error_spec.rb +44 -0
- metadata +142 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'dzl/dsl_proxies/endpoint'
|
2
|
+
|
3
|
+
class Dzl::DSLSubjects::Endpoint < Dzl::DSLSubject
|
4
|
+
attr_reader :pblock, :route_regex, :route, :router, :hooks
|
5
|
+
attr_accessor :handler
|
6
|
+
include Dzl::EndpointDoc
|
7
|
+
|
8
|
+
def initialize(route, opts, router)
|
9
|
+
@route = route
|
10
|
+
@opts = opts
|
11
|
+
@router = router
|
12
|
+
@pblock = Dzl::DSLSubjects::ParameterBlock.new(:anonymous, {}, @router)
|
13
|
+
@pblock.dsl_proxy.import_pblock(:__default)
|
14
|
+
@dsl_proxy = Dzl::DSLProxies::Endpoint.new(self)
|
15
|
+
@hooks = {
|
16
|
+
after_validate: []
|
17
|
+
}
|
18
|
+
|
19
|
+
analyze_route
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json(opts=nil)
|
23
|
+
{
|
24
|
+
opts: @opts,
|
25
|
+
pblock: @pblock
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle(request)
|
30
|
+
request.silent = true if @opts[:silent]
|
31
|
+
Dzl::ResponseContext.new(self, request, @handler).__respond__
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate(request)
|
35
|
+
unless @opts[:request_methods].include?(request.request_method.downcase.to_sym)
|
36
|
+
return Dzl::ValueOrError.new(e: :request_method_not_supported)
|
37
|
+
end
|
38
|
+
|
39
|
+
route_params = extract_route_parameters(request.path)
|
40
|
+
params = {
|
41
|
+
params: request.params.merge(route_params).symbolize_keys,
|
42
|
+
headers: request.headers.symbolize_keys
|
43
|
+
}
|
44
|
+
|
45
|
+
pblock.validate(params, request)
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_route_parameters(path)
|
49
|
+
path_splits = path.split('/')
|
50
|
+
path_splits.delete('')
|
51
|
+
|
52
|
+
return nil if path_splits.size != @route_splits.size
|
53
|
+
|
54
|
+
Hash[
|
55
|
+
*@route_splits.collect do |rsplit|
|
56
|
+
psplit = path_splits.shift
|
57
|
+
next unless rsplit.starts_with?(':')
|
58
|
+
[rsplit[1..-1].to_sym, psplit]
|
59
|
+
end.compact.flatten
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def analyze_route
|
65
|
+
@route = "/#{@route}" if @route.is_a?(Symbol)
|
66
|
+
|
67
|
+
if params = /\/:([^\/]+)/.match(@route)
|
68
|
+
params[1..-1].each {|p| @pblock.dsl_proxy.required(p.to_sym, in_path: true)}
|
69
|
+
end
|
70
|
+
|
71
|
+
@route_splits = @route.split('/').select{|s| not s.empty?}
|
72
|
+
|
73
|
+
route_regex_string = @route_splits.collect do |route_part|
|
74
|
+
route_part.starts_with?(':') ? "/.*?" : "/#{route_part}"
|
75
|
+
end.push('$').join('')
|
76
|
+
|
77
|
+
@route_regex = Regexp.new(route_regex_string)
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Dzl::DSLSubjects::Parameter
|
2
|
+
module AllowedValues
|
3
|
+
def allowed_values(input)
|
4
|
+
unless (@validations[:allowed_values].present? ||
|
5
|
+
@validations[:disallowed_values].present?)
|
6
|
+
return Dzl::ValueOrError.new(v: input)
|
7
|
+
end
|
8
|
+
|
9
|
+
if @validations[:disallowed_values].present?
|
10
|
+
valid = true
|
11
|
+
|
12
|
+
if input.is_a?(Array)
|
13
|
+
valid = input.none? do |value|
|
14
|
+
@validations[:disallowed_values].include?(value)
|
15
|
+
end
|
16
|
+
elsif input.is_a?(String)
|
17
|
+
valid = !@validations[:disallowed_values].include?(input)
|
18
|
+
end
|
19
|
+
|
20
|
+
return Dzl::ValueOrError.new(e: :disallowed_values_failed) unless valid
|
21
|
+
end
|
22
|
+
|
23
|
+
if @validations[:allowed_values].present?
|
24
|
+
valid = true
|
25
|
+
|
26
|
+
if param_type == Array
|
27
|
+
valid = input.all? do |value|
|
28
|
+
@validations[:allowed_values].include?(value)
|
29
|
+
end
|
30
|
+
elsif param_type == String
|
31
|
+
valid = @validations[:allowed_values].include?(input)
|
32
|
+
end
|
33
|
+
|
34
|
+
return Dzl::ValueOrError.new(e: :allowed_values_failed) unless valid
|
35
|
+
end
|
36
|
+
|
37
|
+
Dzl::ValueOrError.new(v: input)
|
38
|
+
end
|
39
|
+
|
40
|
+
def regex_match(input)
|
41
|
+
return Dzl::ValueOrError.new(v: input) unless @validations[:matches].present?
|
42
|
+
|
43
|
+
error = nil
|
44
|
+
|
45
|
+
if input.is_a?(String)
|
46
|
+
unless @validations[:matches].any? {|re| re.match(input)}
|
47
|
+
error = Dzl::ValueOrError.new(e: :regex_match_fail)
|
48
|
+
end
|
49
|
+
elsif input.is_a?(Array)
|
50
|
+
input.each do |v|
|
51
|
+
unless @validations[:matches].any? {|re| re.match(v)}
|
52
|
+
error = Dzl::ValueOrError.new(e: :regex_match_fail)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return error ? error : Dzl::ValueOrError.new(v: input)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Dzl::DSLSubjects::Parameter
|
2
|
+
module TypeConversion
|
3
|
+
def convert_type(input)
|
4
|
+
if param_type == String
|
5
|
+
v = Dzl::ValueOrError.new(v: input)
|
6
|
+
|
7
|
+
if v.value.empty? && @opts[:required]
|
8
|
+
v = Dzl::ValueOrError.new(
|
9
|
+
e: :missing_required_param
|
10
|
+
)
|
11
|
+
else
|
12
|
+
v
|
13
|
+
end
|
14
|
+
elsif param_type == Array
|
15
|
+
v = Dzl::ValueOrError.new(
|
16
|
+
v: input.split(
|
17
|
+
(@opts[:type_opts][:separator] rescue nil) || ' '
|
18
|
+
)
|
19
|
+
)
|
20
|
+
|
21
|
+
if v.value.empty? && @opts[:required]
|
22
|
+
Dzl::ValueOrError.new(
|
23
|
+
e: :empty_required_array
|
24
|
+
)
|
25
|
+
else
|
26
|
+
v
|
27
|
+
end
|
28
|
+
elsif param_type == Integer || param_type == Fixnum
|
29
|
+
if (input = input.to_i.to_s) == input
|
30
|
+
Dzl::ValueOrError.new(v: input.to_i)
|
31
|
+
else
|
32
|
+
Dzl::ValueOrError.new(
|
33
|
+
e: :type_conversion_error
|
34
|
+
)
|
35
|
+
end
|
36
|
+
elsif param_type == Date || param_type == Time
|
37
|
+
input = Time.parse(input) rescue nil
|
38
|
+
if input
|
39
|
+
input = input.to_date if param_type == Date
|
40
|
+
Dzl::ValueOrError.new(v: input)
|
41
|
+
else
|
42
|
+
Dzl::ValueOrError.new(
|
43
|
+
e: :type_conversion_error
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def prevalidate_transform(input)
|
50
|
+
if @validations.has_key?(:prevalidate_transform)
|
51
|
+
@validations[:prevalidate_transform].each do |transform|
|
52
|
+
input = transform.call(input)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Dzl::ValueOrError.new(v: input)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'dzl/dsl_proxies/parameter'
|
2
|
+
|
3
|
+
class Dzl::ParameterError < StandardError; end
|
4
|
+
|
5
|
+
class Dzl::DSLSubjects::Parameter < Dzl::DSLSubject
|
6
|
+
require 'dzl/dsl_subjects/parameter/type_conversion'
|
7
|
+
require 'dzl/dsl_subjects/parameter/allowed_values'
|
8
|
+
include TypeConversion
|
9
|
+
include AllowedValues
|
10
|
+
|
11
|
+
attr_reader :validations, :opts
|
12
|
+
attr_writer :default
|
13
|
+
|
14
|
+
def initialize(name, opts)
|
15
|
+
@name = name
|
16
|
+
@opts = opts
|
17
|
+
@validations = {
|
18
|
+
type: String
|
19
|
+
}
|
20
|
+
@dsl_proxy = Dzl::DSLProxies::Parameter.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def clone
|
24
|
+
deep_copy = self.dup
|
25
|
+
deep_copy.dup_data
|
26
|
+
deep_copy
|
27
|
+
end
|
28
|
+
|
29
|
+
def dup_data
|
30
|
+
@opts = @opts.clone
|
31
|
+
@validations = @validations.clone
|
32
|
+
@dsl_proxy = Dzl::DSLProxies::Parameter.new(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def param_type
|
36
|
+
@validations[:type]
|
37
|
+
end
|
38
|
+
|
39
|
+
def overwrite_opts(opts)
|
40
|
+
if @opts[:in_path] && opts[:required] == false
|
41
|
+
raise Dzl::ParameterError.new("Cannot set in-path param #{name} to optional")
|
42
|
+
end
|
43
|
+
|
44
|
+
@opts.merge!(opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a symbol describe the error if error,
|
48
|
+
# returns the transformed value if not
|
49
|
+
# TODO symbol values?
|
50
|
+
def validate(input)
|
51
|
+
# Validate type
|
52
|
+
unless input
|
53
|
+
if @opts[:required]
|
54
|
+
return Dzl::ValueOrError.new(
|
55
|
+
e: @opts[:header] ? :missing_required_header : :missing_required_param
|
56
|
+
)
|
57
|
+
else
|
58
|
+
return Dzl::ValueOrError.new(
|
59
|
+
v: @opts.has_key?(:default_value) ? @opts[:default_value] : :__no_value__
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
input = convert_type(input)
|
65
|
+
return input if input.error?
|
66
|
+
|
67
|
+
input = prevalidate_transform(input.value)
|
68
|
+
return input if input.error?
|
69
|
+
|
70
|
+
input = allowed_values(input.value)
|
71
|
+
return input if input.error?
|
72
|
+
|
73
|
+
input = regex_match(input.value)
|
74
|
+
return input if input.error?
|
75
|
+
|
76
|
+
# Validator procs
|
77
|
+
if @validations.has_key?(:procs)
|
78
|
+
@validations[:procs].each do |vproc|
|
79
|
+
vproc.call(input.value) or
|
80
|
+
return Dzl::ValueOrError.new(e: :validator_poc_failed)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Validator classes
|
85
|
+
@validations.select {|k, v| v.kind_of?(Dzl::Validator)}.each do |vary|
|
86
|
+
name, validator = vary
|
87
|
+
input = validator.validate(input.value)
|
88
|
+
return input if input.error?
|
89
|
+
end
|
90
|
+
|
91
|
+
Dzl::ValueOrError.new(v: input.value)
|
92
|
+
end
|
93
|
+
|
94
|
+
def as_json(opts=nil)
|
95
|
+
{
|
96
|
+
opts: @opts,
|
97
|
+
validations: @validations
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'dzl/dsl_proxies/parameter_block'
|
2
|
+
|
3
|
+
class Dzl::DSLSubjects::ParameterBlock < Dzl::DSLSubject
|
4
|
+
attr_accessor :params
|
5
|
+
attr_reader :router
|
6
|
+
|
7
|
+
def initialize(name, opts, router)
|
8
|
+
@name = name
|
9
|
+
@opts = opts
|
10
|
+
@router = router
|
11
|
+
@params = {}
|
12
|
+
@dsl_proxy = Dzl::DSLProxies::ParameterBlock.new(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate(parandidates, request)
|
16
|
+
errors = @params.each_with_object({}) do |pary, errors|
|
17
|
+
pname, param = pary
|
18
|
+
parandidate_key = param.opts[:header] ? :headers : :params
|
19
|
+
|
20
|
+
# verror = value or error.
|
21
|
+
verror = @params[pname].validate(parandidates[parandidate_key][pname])
|
22
|
+
if verror.error?
|
23
|
+
errors[pname] = verror.error
|
24
|
+
else
|
25
|
+
parandidates[parandidate_key][pname] = verror.value unless verror.value == :__no_value__
|
26
|
+
end
|
27
|
+
end || {}
|
28
|
+
|
29
|
+
# Check for extra request params we are not expecting
|
30
|
+
parandidates[:params].each do |pname, value|
|
31
|
+
unless @params.keys.include?(pname)
|
32
|
+
parandidates[:params].delete(pname)
|
33
|
+
errors[pname] = :unknown_param
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if !errors.empty?
|
38
|
+
Dzl::ValueOrError.new(e: errors)
|
39
|
+
elsif @opts[:protection]
|
40
|
+
protection_errors = @opts[:protection].collect do |protection|
|
41
|
+
protection.allow?(parandidates, request)
|
42
|
+
end.select { |result| result.error? }
|
43
|
+
|
44
|
+
if protection_errors.empty?
|
45
|
+
Dzl::ValueOrError.new(v: parandidates)
|
46
|
+
else
|
47
|
+
protection_errors[0]
|
48
|
+
end
|
49
|
+
else
|
50
|
+
Dzl::ValueOrError.new(v: parandidates)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"pblock:#{name}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def as_json(opts=nil)
|
59
|
+
{
|
60
|
+
opts: @opts,
|
61
|
+
params: @params
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'dzl/dsl_proxies/protection'
|
2
|
+
|
3
|
+
class Dzl::RespondWithHTTPBasicChallenge < StandardError; end
|
4
|
+
|
5
|
+
class Dzl::DSLSubjects::Protection < Dzl::DSLSubject
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
@dsl_proxy = Dzl::DSLProxies::Protection.new(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def allow?(parandidates, request)
|
12
|
+
params = parandidates[:params]
|
13
|
+
headers = parandidates[:headers]
|
14
|
+
|
15
|
+
if @opts[:http_basic].present?
|
16
|
+
@auth = Rack::Auth::Basic::Request.new(request.env)
|
17
|
+
if @auth.provided? && @auth.basic? && @auth.credentials
|
18
|
+
unless @auth.credentials[0] == @opts[:http_basic][:username] &&
|
19
|
+
@auth.credentials[1] == @opts[:http_basic][:password]
|
20
|
+
Dzl::ValueOrError.new(e: :invalid_http_basic_credentials)
|
21
|
+
else
|
22
|
+
Dzl::ValueOrError.new(v: nil)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
Dzl::ValueOrError.new(e: :no_http_basic_credentials)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
Dzl::ValueOrError.new(v: nil)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'dzl/dsl_proxies/router'
|
2
|
+
require 'dzl/dsl_subjects/defaults'
|
3
|
+
|
4
|
+
class Dzl::DSLSubjects::Router < Dzl::DSLSubject
|
5
|
+
include Dzl::RouterDoc
|
6
|
+
attr_reader :pblocks, :defaults_dslsub, :defaults, :app
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@pblocks = {}
|
10
|
+
@endpoints_by_route = {}
|
11
|
+
@stack = []
|
12
|
+
@defaults = {}
|
13
|
+
@defaults_dslsub = Dzl::DSLSubjects::Defaults.new(self)
|
14
|
+
@dsl_proxy = Dzl::DSLProxies::Router.new(self)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call_with_subject(proc, subject)
|
19
|
+
@stack.push(subject)
|
20
|
+
proc.call
|
21
|
+
@stack.pop
|
22
|
+
end
|
23
|
+
|
24
|
+
def subject
|
25
|
+
@stack.last
|
26
|
+
end
|
27
|
+
|
28
|
+
def routes
|
29
|
+
@endpoints_by_route.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
def endpoints
|
33
|
+
@endpoints = @endpoints_by_route.values.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_endpoint(ept)
|
37
|
+
@endpoints_by_route[ept.route] ||= []
|
38
|
+
@endpoints_by_route[ept.route] << ept
|
39
|
+
end
|
40
|
+
|
41
|
+
def pblocks
|
42
|
+
@pblocks
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_pblock(pb)
|
46
|
+
@pblocks[pb.name] = pb
|
47
|
+
end
|
48
|
+
|
49
|
+
def as_json(opts=nil)
|
50
|
+
@endpoints
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_request(request)
|
54
|
+
endpoint = find_endpoint(request)
|
55
|
+
response = request.handle_with_endpoint(endpoint)
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_endpoint(request)
|
59
|
+
errors = {}
|
60
|
+
raise Dzl::NotFound if routes.empty?
|
61
|
+
|
62
|
+
endpoint = endpoints.find do |endpoint|
|
63
|
+
if request.path.match(endpoint.route_regex)
|
64
|
+
validation = endpoint.validate(request)
|
65
|
+
if validation.value?
|
66
|
+
# use our validated/transformed/params
|
67
|
+
request.params_and_headers_for_endpoint(
|
68
|
+
endpoint,
|
69
|
+
validation.value
|
70
|
+
)
|
71
|
+
true
|
72
|
+
else
|
73
|
+
errors[endpoint.route] = validation.error
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
if !errors.empty? &&
|
80
|
+
errors.values.any? {|v| v == :no_http_basic_credentials || v == :invalid_http_basic_credentials}
|
81
|
+
raise Dzl::RespondWithHTTPBasicChallenge
|
82
|
+
end
|
83
|
+
|
84
|
+
endpoint || raise(Dzl::NotFound.new(errors))
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
data/lib/dzl/errors.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Dzl::Error < StandardError
|
2
|
+
attr_reader :data, :status
|
3
|
+
|
4
|
+
def initialize(data = {})
|
5
|
+
@data = data
|
6
|
+
@status = 500
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_json
|
10
|
+
{
|
11
|
+
status: @status,
|
12
|
+
error_class: self.class.to_s,
|
13
|
+
errors: @data,
|
14
|
+
trace: self.backtrace
|
15
|
+
}.to_json
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Dzl::RequestError < Dzl::Error; end
|
20
|
+
|
21
|
+
class Dzl::NotFound < Dzl::RequestError
|
22
|
+
def initialize(data = {})
|
23
|
+
super(data)
|
24
|
+
@status = 404
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Dzl::BadRequest < Dzl::RequestError
|
29
|
+
def initialize(data = {})
|
30
|
+
super(data)
|
31
|
+
@status = 400
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::FunWithHandlers < Dzl::Examples::Base
|
4
|
+
defaults do
|
5
|
+
content_type 'application/json'
|
6
|
+
end
|
7
|
+
|
8
|
+
endpoint '/say_bar' do
|
9
|
+
optional :foo, :bar, :baz, :bam
|
10
|
+
|
11
|
+
handle do
|
12
|
+
params[:bar]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
endpoint '/say_bar_and_api_key' do
|
17
|
+
required :bar
|
18
|
+
required_header :api_key
|
19
|
+
|
20
|
+
handle do
|
21
|
+
{
|
22
|
+
bar: params[:bar],
|
23
|
+
api_key: headers[:api_key]
|
24
|
+
}.to_json
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/raise' do
|
29
|
+
handle do
|
30
|
+
raise 'omg'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::FunWithHooks < Dzl::Examples::Base
|
4
|
+
defaults do
|
5
|
+
content_type 'application/json'
|
6
|
+
end
|
7
|
+
|
8
|
+
endpoint '/pre' do
|
9
|
+
required :foo do
|
10
|
+
type Fixnum
|
11
|
+
value >= 4
|
12
|
+
prevalidate_transform do |input|
|
13
|
+
input == 1 ? 4 : input
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
endpoint '/post' do
|
19
|
+
required :foo do
|
20
|
+
type Fixnum
|
21
|
+
value >= 4
|
22
|
+
end
|
23
|
+
|
24
|
+
after_validate do
|
25
|
+
params[:foo] *= 2
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
endpoint '/multiply' do
|
30
|
+
required :x, :y do
|
31
|
+
type Fixnum
|
32
|
+
end
|
33
|
+
|
34
|
+
after_validate do
|
35
|
+
params[:z] = params[:x] * params[:y]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
endpoint '/omg_math' do
|
40
|
+
optional :x, :y, :z do
|
41
|
+
type Fixnum
|
42
|
+
end
|
43
|
+
|
44
|
+
optional :prefix
|
45
|
+
|
46
|
+
# NEVER DO THIS IN YOUR APP IT IS SO UGLY
|
47
|
+
after_validate do
|
48
|
+
params[:multiply_then_add] = params[:x] * params[:y]
|
49
|
+
end
|
50
|
+
|
51
|
+
after_validate do
|
52
|
+
params[:multiply_then_add] += params[:z]
|
53
|
+
end
|
54
|
+
|
55
|
+
after_validate do
|
56
|
+
params[:speak] = "#{params[:prefix]} #{params[:multiply_then_add]}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
endpoint '/vomit' do
|
61
|
+
after_validate do
|
62
|
+
raise Dzl::BadRequest.new("This isn't quite what I was expecting")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::FunWithParams < Dzl::Examples::Base
|
4
|
+
endpoint '/foo' do
|
5
|
+
required :foo do
|
6
|
+
type Array
|
7
|
+
disallowed_values %w{zilch zip nada}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
endpoint '/bar' do
|
12
|
+
required :foo do
|
13
|
+
type Array, separator: '+'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
endpoint '/baz' do
|
18
|
+
required :foo do
|
19
|
+
type Array, separator: ','
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
endpoint '/bar' do
|
24
|
+
required :foo
|
25
|
+
end
|
26
|
+
|
27
|
+
endpoint '/foo/:bar' do
|
28
|
+
required :bar do
|
29
|
+
type Time
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
endpoint '/protected' do
|
34
|
+
protect do
|
35
|
+
http_basic username: 'no', password: 'way'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
endpoint '/arithmetic' do
|
40
|
+
optional :int do
|
41
|
+
type Fixnum
|
42
|
+
value >= 5
|
43
|
+
end
|
44
|
+
|
45
|
+
optional :str do
|
46
|
+
value == 'hello'
|
47
|
+
end
|
48
|
+
|
49
|
+
optional :date do
|
50
|
+
type Date
|
51
|
+
value > Date.parse('2012-01-01')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
endpoint '/defaults' do
|
56
|
+
optional :foo do
|
57
|
+
default 'hello'
|
58
|
+
end
|
59
|
+
|
60
|
+
optional :bar
|
61
|
+
optional :baz do
|
62
|
+
default 'world'
|
63
|
+
end
|
64
|
+
|
65
|
+
optional :nil do
|
66
|
+
default nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
endpoint '/foo/:bar'
|
71
|
+
end
|