rack-parser 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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, :content_types => {
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.
@@ -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
- attr_reader :content_types
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 = app
35
- @content_types = DEFAULT_CONTENT_TYPE.merge(options.delete(: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 # Send to logger if its there.
53
- meth = "to_#{format}"
54
- meth = "inspect" unless Hash.respond_to? meth
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
 
@@ -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.4"
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"
@@ -54,13 +54,25 @@ context "Rack::Parser" do
54
54
  asserts(:body).equals({'foo' => 'bar'}.inspect)
55
55
  end
56
56
 
57
- context "with bad data" do
58
- setup do
59
- post '/post', "fuuuuuuuuuu", { 'CONTENT_TYPE' => 'application/json' }
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
- asserts(:status).equals 400
63
- asserts(:body).equals "{\"errors\":\"706: unexpected token at 'fuuuuuuuuuu'\"}"
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
@@ -24,7 +24,13 @@ class Riot::Situation
24
24
  }
25
25
 
26
26
  builder = Rack::Builder.new
27
- builder.use Rack::Parser, :content_types => { 'application/foo' => Proc.new { |b| {'foo' => 'bar'} } }
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
- date: 2011-07-15 00:00:00 Z
14
- dependencies:
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
- prerelease: false
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: "0"
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
- requirement: &id002 !ruby/object:Gem::Requirement
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: "0"
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
- requirement: &id003 !ruby/object:Gem::Requirement
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: "0"
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
- requirement: &id004 !ruby/object:Gem::Requirement
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: "0"
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
- requirement: &id005 !ruby/object:Gem::Requirement
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: "0"
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
- requirement: &id006 !ruby/object:Gem::Requirement
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: "0"
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
79
77
  type: :development
80
- version_requirements: *id006
81
- description: Rack Middleware for parsing post body data for json/xml and various content types
82
- email:
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: "0"
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: "0"
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.4
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