rack-parser 0.0.4 → 0.1.0
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/README.md +31 -5
- data/lib/rack/parser.rb +30 -10
- data/rack-parser.gemspec +1 -1
- data/test/parser_test.rb +17 -5
- data/test/teststrap.rb +7 -1
- metadata +71 -77
data/README.md
CHANGED
@@ -32,14 +32,12 @@ In a Sinatra or [Padrino](http://padrinorb.com) application, it would probably b
|
|
32
32
|
```ruby
|
33
33
|
# app.rb
|
34
34
|
|
35
|
-
use Rack::Parser
|
36
|
-
'application/json' => Proc.new { |body| MultiJson.decode body },
|
37
|
-
'application/xml' => Proc.new { |body| MultiXml.decode body },
|
38
|
-
'application/roll' => Proc.new { |body| 'never gonna give you up' }
|
39
|
-
}
|
35
|
+
use Rack::Parser
|
40
36
|
```
|
41
37
|
|
42
38
|
|
39
|
+
### Content Type Parsing ###
|
40
|
+
|
43
41
|
By default, Rack::Parser uses MultiJson and MultiXml to decode/parse
|
44
42
|
your JSON/XML Data. these can be overwritten if you choose not to use
|
45
43
|
them. However, through using them you can just as easily leverage the
|
@@ -69,6 +67,29 @@ use Rack::Parser, :content_types => {
|
|
69
67
|
}
|
70
68
|
```
|
71
69
|
|
70
|
+
### Error Handling ###
|
71
|
+
|
72
|
+
Rack::Parser comes with a default error handling response that is sent
|
73
|
+
if an error is to occur. If a `logger` is present, it will try to `warn`
|
74
|
+
with the content type and error message.
|
75
|
+
|
76
|
+
You can additionally customize the error handling response as well to
|
77
|
+
whatever it is you like:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
use Rack::Parser, :error_responses => {
|
81
|
+
'default' => Proc.new { |e, content_type| [500, {}, ["boo hoo"] ] },
|
82
|
+
'application/json' => Proc.new { |e, content_type| [400, {'Content-Type'=>content_type}, ["broke"]] }
|
83
|
+
}
|
84
|
+
```
|
85
|
+
|
86
|
+
The error handler expects to pass both the `error` and `content_type` so
|
87
|
+
that you can use them within your responses. In addition, you can
|
88
|
+
override the default response as well.
|
89
|
+
|
90
|
+
If no content_type error handling response is present, it will use the
|
91
|
+
`default`.
|
92
|
+
|
72
93
|
## Inspirations ##
|
73
94
|
|
74
95
|
This project came to being because of:
|
@@ -76,6 +97,11 @@ This project came to being because of:
|
|
76
97
|
* [Niko Dittmann's](https://www.github.com/niko) [rack-post-body-to-params](https://www.github.com/niko/rack-post-body-to-params) which some of its ideas are instilled in this middleware.
|
77
98
|
* Rack::PostBodyContentTypeParser from rack-contrib which proved to be an inspiration for both libraries.
|
78
99
|
|
100
|
+
|
101
|
+
## Contributors ##
|
102
|
+
|
103
|
+
* [Stephen Becker IV](https://github.com/sbeckeriv) - For initial custom error response handling work.
|
104
|
+
|
79
105
|
## Copyright
|
80
106
|
|
81
107
|
Copyright © 2011 Arthur Chiu. See [MIT-LICENSE](https://github.com/achiu/rack-parser/blob/master/MIT-LICENSE) for details.
|
data/lib/rack/parser.rb
CHANGED
@@ -8,6 +8,8 @@ module Rack
|
|
8
8
|
# designate any engine you wish that is compatible with the MultiJson/MultiXml libraries.
|
9
9
|
# You can also conveniently use another library by as well by wrapping it as a Proc or add additional
|
10
10
|
# content types which are not default in this middleware.
|
11
|
+
# In addition, you can set custom error handling for each content_type. If no error response is defined for
|
12
|
+
# a particular content_type, it will use the default error response, which can also be overrided.
|
11
13
|
#
|
12
14
|
class Parser
|
13
15
|
|
@@ -22,17 +24,37 @@ module Rack
|
|
22
24
|
'application/json' => Proc.new { |body| MultiJson.decode(body) }
|
23
25
|
}
|
24
26
|
|
25
|
-
|
27
|
+
DEFAULT_ERROR_RESPONSE = {
|
28
|
+
'default' =>
|
29
|
+
Proc.new do |e, content_type|
|
30
|
+
format = content_type.split('/').last
|
31
|
+
meth = "to_#{format}"
|
32
|
+
meth = "inspect" unless ::Hash.respond_to? meth
|
33
|
+
[400, {'Content-Type' => content_type }, [ { 'errors' => e.to_s }.method(meth).call ] ]
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
attr_reader :content_types, :error_responses
|
26
38
|
|
27
39
|
# Usage:
|
28
|
-
# use Rack::Parser, :content_types
|
40
|
+
# use Rack::Parser, :content_types => {
|
29
41
|
# 'application/xml' => Proc.new { |body| XmlParser.parse body } # if you don't want the default
|
30
42
|
# 'application/json' => Proc.new { |body| JsonParser.decode body } # if you don't want the default
|
31
|
-
# 'application/foo' => Proc.new { |body| FooParser.parse body }
|
43
|
+
# 'application/foo' => Proc.new { |body| FooParser.parse body } # Add custom content_types to parse.
|
32
44
|
# }
|
45
|
+
#
|
46
|
+
# # use Rack::Parser,
|
47
|
+
# :content_types => {
|
48
|
+
# 'application/xml' => Proc.new { |body| XmlParser.parse body } # if you don't want the default
|
49
|
+
# },
|
50
|
+
# :error_responses => {
|
51
|
+
# 'default' => Proc.new { |e, content_type| [500, {}, ["boo hoo"] ] }, # Override the default error response..
|
52
|
+
# 'application/json' => Proc.new { |e, content_type| [400, {'Content-Type'=>content_type}, ["broke"]] } # Customize error responses based on content type.
|
53
|
+
# }
|
33
54
|
def initialize(app, options = {})
|
34
|
-
@app
|
35
|
-
@content_types
|
55
|
+
@app = app
|
56
|
+
@content_types = DEFAULT_CONTENT_TYPE.merge(options.delete(:content_types) || {})
|
57
|
+
@error_responses = DEFAULT_ERROR_RESPONSE.merge(options.delete(:error_responses) || {})
|
36
58
|
end
|
37
59
|
|
38
60
|
def call(env)
|
@@ -43,16 +65,14 @@ module Rack
|
|
43
65
|
body = env[POST_BODY].read
|
44
66
|
return @app.call(env) if (body.respond_to?(:empty?) ? body.empty? : !body) # Send it down the stack immediately
|
45
67
|
content_type = Rack::Request.new(env).media_type
|
46
|
-
format = content_type.split('/').last
|
47
68
|
begin
|
48
69
|
result = @content_types[content_type].call(body)
|
49
70
|
env.update FORM_HASH => result, FORM_INPUT => env[POST_BODY]
|
50
71
|
@app.call env
|
51
72
|
rescue Exception => e
|
52
|
-
logger.warn "#{self.class} #{content_type} parsing error: #{e.to_s}" if respond_to? :logger
|
53
|
-
|
54
|
-
|
55
|
-
[400, { 'Content-Type' => content_type }, [ {'errors' => e.to_s}.method(meth).call ] ] # Finally, return an error response.
|
73
|
+
logger.warn "#{self.class} #{content_type} parsing error: #{e.to_s}" if respond_to? :logger # Send to logger if its there.
|
74
|
+
err = @error_responses[content_type] ? content_type : 'default'
|
75
|
+
@error_responses[err].call(e, content_type) # call the error responses
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
data/rack-parser.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "rack-parser"
|
6
|
-
s.version = "0.0
|
6
|
+
s.version = "0.1.0"
|
7
7
|
s.authors = ["Arthur Chiu"]
|
8
8
|
s.email = ["mr.arthur.chiu@gmail.com"]
|
9
9
|
s.homepage = "https://www.github.com/achiu/rack-parser"
|
data/test/parser_test.rb
CHANGED
@@ -54,13 +54,25 @@ context "Rack::Parser" do
|
|
54
54
|
asserts(:body).equals({'foo' => 'bar'}.inspect)
|
55
55
|
end
|
56
56
|
|
57
|
-
context "
|
58
|
-
|
59
|
-
|
57
|
+
context "for errors" do
|
58
|
+
|
59
|
+
context "with default error message" do
|
60
|
+
setup do
|
61
|
+
post '/post', "fuuuuuuuuuu", { 'CONTENT_TYPE' => 'application/json' }
|
62
|
+
end
|
63
|
+
|
64
|
+
asserts(:status).equals 400
|
65
|
+
asserts(:body).equals "{\"errors\":\"710: unexpected token at 'fuuuuuuuuuu'\"}"
|
60
66
|
end
|
61
67
|
|
62
|
-
|
63
|
-
|
68
|
+
context "with custom default error message" do
|
69
|
+
setup do
|
70
|
+
post '/post', "fuuuuuuuuuu", { 'CONTENT_TYPE' => 'application/wahh' }
|
71
|
+
end
|
72
|
+
|
73
|
+
asserts(:status).equals 500
|
74
|
+
asserts(:body).equals "wahh"
|
75
|
+
end
|
64
76
|
end
|
65
77
|
|
66
78
|
end
|
data/test/teststrap.rb
CHANGED
@@ -24,7 +24,13 @@ class Riot::Situation
|
|
24
24
|
}
|
25
25
|
|
26
26
|
builder = Rack::Builder.new
|
27
|
-
builder.use Rack::Parser,
|
27
|
+
builder.use Rack::Parser,
|
28
|
+
:content_types => {
|
29
|
+
'application/foo' => Proc.new { |b| {'foo' => 'bar'} }
|
30
|
+
},
|
31
|
+
:error_responses => {
|
32
|
+
'application/wahh' => Proc.new { |e, content_type| [500,{'Content-Type' => content_type},['wahh']]}
|
33
|
+
}
|
28
34
|
builder.run main_app
|
29
35
|
builder.to_app
|
30
36
|
end
|
metadata
CHANGED
@@ -1,93 +1,90 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-parser
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.4
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Arthur Chiu
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-08-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
16
15
|
name: rack
|
17
|
-
|
18
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &2152833180 !ruby/object:Gem::Requirement
|
19
17
|
none: false
|
20
|
-
requirements:
|
21
|
-
- -
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version:
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
24
22
|
type: :runtime
|
25
|
-
version_requirements: *id001
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: multi_json
|
28
23
|
prerelease: false
|
29
|
-
|
24
|
+
version_requirements: *2152833180
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: multi_json
|
27
|
+
requirement: &2152832740 !ruby/object:Gem::Requirement
|
30
28
|
none: false
|
31
|
-
requirements:
|
32
|
-
- -
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version:
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
35
33
|
type: :runtime
|
36
|
-
version_requirements: *id002
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: multi_xml
|
39
34
|
prerelease: false
|
40
|
-
|
35
|
+
version_requirements: *2152832740
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: multi_xml
|
38
|
+
requirement: &2152832320 !ruby/object:Gem::Requirement
|
41
39
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version:
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
46
44
|
type: :runtime
|
47
|
-
version_requirements: *id003
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: riot
|
50
45
|
prerelease: false
|
51
|
-
|
46
|
+
version_requirements: *2152832320
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: riot
|
49
|
+
requirement: &2152831900 !ruby/object:Gem::Requirement
|
52
50
|
none: false
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version:
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
57
55
|
type: :development
|
58
|
-
version_requirements: *id004
|
59
|
-
- !ruby/object:Gem::Dependency
|
60
|
-
name: rack-test
|
61
56
|
prerelease: false
|
62
|
-
|
57
|
+
version_requirements: *2152831900
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rack-test
|
60
|
+
requirement: &2152831480 !ruby/object:Gem::Requirement
|
63
61
|
none: false
|
64
|
-
requirements:
|
65
|
-
- -
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version:
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
68
66
|
type: :development
|
69
|
-
version_requirements: *id005
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: json
|
72
67
|
prerelease: false
|
73
|
-
|
68
|
+
version_requirements: *2152831480
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: json
|
71
|
+
requirement: &2152831060 !ruby/object:Gem::Requirement
|
74
72
|
none: false
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
version:
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
79
77
|
type: :development
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2152831060
|
80
|
+
description: Rack Middleware for parsing post body data for json/xml and various content
|
81
|
+
types
|
82
|
+
email:
|
83
83
|
- mr.arthur.chiu@gmail.com
|
84
84
|
executables: []
|
85
|
-
|
86
85
|
extensions: []
|
87
|
-
|
88
86
|
extra_rdoc_files: []
|
89
|
-
|
90
|
-
files:
|
87
|
+
files:
|
91
88
|
- .gitignore
|
92
89
|
- Gemfile
|
93
90
|
- MIT-LICENSE
|
@@ -99,31 +96,28 @@ files:
|
|
99
96
|
- test/teststrap.rb
|
100
97
|
homepage: https://www.github.com/achiu/rack-parser
|
101
98
|
licenses: []
|
102
|
-
|
103
99
|
post_install_message:
|
104
100
|
rdoc_options: []
|
105
|
-
|
106
|
-
require_paths:
|
101
|
+
require_paths:
|
107
102
|
- lib
|
108
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
104
|
none: false
|
110
|
-
requirements:
|
111
|
-
- -
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
version:
|
114
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
110
|
none: false
|
116
|
-
requirements:
|
117
|
-
- -
|
118
|
-
- !ruby/object:Gem::Version
|
119
|
-
version:
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
120
115
|
requirements: []
|
121
|
-
|
122
116
|
rubyforge_project: rack-parser
|
123
|
-
rubygems_version: 1.8.
|
117
|
+
rubygems_version: 1.8.6
|
124
118
|
signing_key:
|
125
119
|
specification_version: 3
|
126
120
|
summary: Rack Middleware for parsing post body data
|
127
|
-
test_files:
|
121
|
+
test_files:
|
128
122
|
- test/parser_test.rb
|
129
123
|
- test/teststrap.rb
|