rack-bodyparser 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 743caf986aba0bf3b1de5f82ebf7939f4163cc2f
4
+ data.tar.gz: 687565e7eaec8e87c5d5d17a728f3dfa800ba4c2
5
+ SHA512:
6
+ metadata.gz: 214c1fc24ac38fab23bfd4c2fb54435403058eb93c62fa2bd5613bc2990e3447fb2149af7afd5bc0156baae0079163ade0d51ff622e56ea3b485abbabec15df1
7
+ data.tar.gz: 44c165eb469358d64021a4ee0b393925da606c5896463cb769e49158b5a6da1a844bf004b16637a74a527a79b43de6227c8333b3bd49c1cc3ae04d12dc53ab20
@@ -0,0 +1 @@
1
+ *.gem
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Aaron Heesakkers
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,134 @@
1
+ # Rack::BodyParser #
2
+
3
+ Rack middleware that provides a way to parse the request body without touching
4
+ `params` or `request.params`.
5
+
6
+
7
+ Instead the parser output is available through `env['parsed_body']` or
8
+ optionally through the Rack::Request object as `request.parsed_body` and/or
9
+ a custom attribute per parser.
10
+
11
+ Rack::BodyParser is heavily inspired by
12
+ [Rack::Parser](https://github.com/achiu/rack-parser).
13
+
14
+ ## Key Features (differences to Rack::Parser) ##
15
+
16
+ 1. separation of `params`/`request.params` and the `parsed_body`.
17
+ 1. (optional) patching of `Rack::Request`:
18
+
19
+ Access parsed payload through `request.parsed_body` with support
20
+ for custom `request.#{your_key_here}` per parser.
21
+ Enable with `:patch_request => true`.
22
+
23
+ Note: Rack::BodyParser **does** **not** contain any parsers by out of the box.
24
+
25
+ ## Installation ##
26
+
27
+ Via rubygems:
28
+
29
+ `gem install rack-bodyparser`
30
+
31
+ ## Usage ##
32
+
33
+ Define your parsers per content_type.
34
+
35
+ Rack::BodyParser accepts `String` or `Regexp` keys as content_type,
36
+ and anything that `respond_to? 'call'` as parser.
37
+
38
+ Sinatra example:
39
+
40
+ ```ruby
41
+ # app.rb
42
+
43
+ use Rack::BodyParser, :parsers => {
44
+ 'application/json' => proc { |data| JSON.parse data },
45
+ 'application/xml' => proc { |data| XML.parse data },
46
+ %r{msgpack} => proc { |data| Msgpack.parse data }
47
+ }
48
+
49
+ post '/' do
50
+ puts env['parsed_body']
51
+ end
52
+ ```
53
+
54
+ ### Error Handling ###
55
+
56
+ Rack::BodyParser has one default error handler that can be overridden by
57
+ setting the 'default' handler. These works like `:parsers`. Use a `String` or
58
+ `Regexp` as content_type key and anything that `respond_to? 'call'` as the
59
+ error handler. The error handler must accept the two parameters
60
+ `Error` and `type` (the content type).
61
+
62
+ ```ruby
63
+ use Rack::Parser, :handlers => {
64
+ 'default' => proc { |e, type|
65
+ [400, {}, ['[Rack::BodyParser] Failed to parse %s: %s' % [type, e.to_s]]]
66
+ }
67
+ }
68
+ ```
69
+
70
+ Rack::BodyParsers will try to `warn` of a `logger` is present.
71
+
72
+ Note: the error handler rescues exceptions that are descents of `StandardError`.
73
+ See http://www.mikeperham.com/2012/03/03/the-perils-of-rescue-exception/
74
+
75
+ ## Patch Rack::Request ##
76
+
77
+ Setting up Rack::BodyParser with `:patch_request => true` will add
78
+ a `parsed_body` method to Rack::Request. Parsers can also provide a
79
+ `:rack_request_key` to define a custom key per parser:
80
+
81
+ ```ruby
82
+
83
+ # gem 'jsonapi_parser'
84
+ require 'json/api' # JSONAPI document parser/validator
85
+ module Rack::BodyParser::JSONAPI
86
+ module Parser
87
+ # This defines the getter key for Rack::Request
88
+ def self.rack_request_key; :document; end
89
+
90
+ def self.call(body)
91
+ JSON::API.parse(JSON.parse(body))
92
+ end
93
+ end
94
+
95
+ module Error
96
+ def self.call(e, type)
97
+ payload = {
98
+ errors: {
99
+ title: 'Failed to parse body as JSONAPI document',
100
+ detail: e.message
101
+ }
102
+ }.to_json
103
+ [422, {}, [payload]]
104
+ end
105
+ end
106
+ end
107
+
108
+ use Rack::BodyParser, :patch_request => true,
109
+ :parsers => {
110
+ 'application/vnd.api+json' => Rack::BodyParser::JSONAPI::Parser
111
+ },
112
+ :handlers => {
113
+ 'application/vnd.api+json' => Rack::BodyParser::JSONAPI::Error
114
+ }
115
+
116
+ post '/' do
117
+ # These all output the same
118
+ puts env['parsed_body']
119
+ puts request.parsed_body
120
+ puts request.document
121
+ end
122
+ ```
123
+
124
+ ## Inspirations ##
125
+
126
+ This project is heavily inspired by [Rack::Parser](https://github.com/achiu/rack-parser). I built
127
+ this because I did not want to mix `params` and the body payload.
128
+
129
+ ## Copyright
130
+
131
+ `Copyright © 2016 Aaron Heesakkers.`
132
+
133
+ See [MIT-LICENSE](https://github.com/aars/rack-bodyparser/blob/master/MIT-LICENSE) for details.
134
+
@@ -0,0 +1,62 @@
1
+ module Rack
2
+ class BodyParser
3
+ # Where to get input.
4
+ REQUEST_BODY = 'rack.input'.freeze
5
+ # Where to store in env
6
+ RACK_ENV_KEY = 'parsed_body'.freeze
7
+ # Where to store in Rack::Request in case of options[:patch_request]
8
+ RACK_REQUEST_KEY = 'parsed_body'.freeze
9
+
10
+ # Default error handler
11
+ ERROR_MESSAGE = "[Rack::BodyParser] Failed to parse %s: %s\n"
12
+ ERROR_HANDLER = proc { |e, type|
13
+ [400, {}, [ERROR_MESSAGE % [type, e.to_s]]]
14
+ }
15
+ attr_reader :parsers, :handlers, :logger
16
+
17
+ def initialize(app, options = {})
18
+ @app = app
19
+ @parsers = options.delete(:parsers) || {}
20
+ @handlers = options.delete(:handlers) || {}
21
+ @handlers = {'default' => ERROR_HANDLER}.merge(@handlers)
22
+ @options = options
23
+ end
24
+
25
+ def call(env)
26
+ type = Rack::Request.new(env).media_type
27
+ parser = type && detect(parsers, type)
28
+ body = parser && env[REQUEST_BODY].read; env[REQUEST_BODY].rewind
29
+ if body && !body.empty?
30
+ parser = parser.last
31
+ begin
32
+ parsed = parser.call body
33
+ env.update RACK_ENV_KEY => parsed
34
+ patch_rack_request parser, parsed if @options[:patch_request]
35
+ rescue StandardError => e
36
+ warn! e, type
37
+ handler = (detect(handlers, type) || detect(handlers, 'default')).last
38
+ return handler.call e, type
39
+ end
40
+ end
41
+ @app.call env
42
+ end
43
+
44
+ def patch_rack_request(parser, parsed)
45
+ if parser.respond_to?(:rack_request_key)
46
+ Rack::Request.send(:define_method, parser.rack_request_key) { parsed }
47
+ end
48
+ Rack::Request.send(:define_method, RACK_REQUEST_KEY) { parsed }
49
+ end
50
+
51
+ def detect(hash, what)
52
+ hash.detect { |match, _|
53
+ match.is_a?(Regexp) ? what.match(match) : what.eql?(match)
54
+ }
55
+ end
56
+
57
+ def warn!(e, type)
58
+ return unless logger
59
+ logger.warn ERROR_MESSAGE % [type, e.to_s]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class BodyParser
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'rack/bodyparser/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'rack-bodyparser'
7
+ s.version = Rack::BodyParser::VERSION
8
+ s.authors = ['Aaron Heesakkers']
9
+ s.email = ['aaronheesakkers@gmail.com']
10
+ s.license = 'MIT'
11
+ s.homepage = 'https://www.github.com/aars/rack-bodyparser'
12
+ s.summary = 'Rack Middleware for parsing request body'
13
+ s.description = %(
14
+ Rack Middleware for parsing request body without touching request.params.
15
+ Allowing full separation of query_string params and body payload.
16
+ )
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
21
+ s.require_paths = ['lib']
22
+
23
+ s.add_dependency 'rack'
24
+ s.add_development_dependency 'minitest'
25
+ s.add_development_dependency 'rack-test'
26
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-bodyparser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Heesakkers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: "\n Rack Middleware for parsing request body without touching request.params.\n
56
+ \ Allowing full separation of query_string params and body payload.\n "
57
+ email:
58
+ - aaronheesakkers@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - MIT-LICENSE
65
+ - README.md
66
+ - lib/rack/bodyparser.rb
67
+ - lib/rack/bodyparser/version.rb
68
+ - rack-bodyparser.gemspec
69
+ homepage: https://www.github.com/aars/rack-bodyparser
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.6.10
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Rack Middleware for parsing request body
93
+ test_files: []