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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.md +134 -0
- data/lib/rack/bodyparser.rb +62 -0
- data/lib/rack/bodyparser/version.rb +5 -0
- data/rack-bodyparser.gemspec +26 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/MIT-LICENSE
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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,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: []
|