dzl 1.0.0.beta0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|