olive_branch 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b54d1b0e0db59e223cf8720ae8b1c886c8f687b6
4
- data.tar.gz: 77114b9066d6498f3497c46c684d1b86fc406f77
3
+ metadata.gz: 7b70147d89c1ed39a3d2622ace5dd0465cf0e859
4
+ data.tar.gz: 8ddd953cdb4b3d83dcc8f76181c021d527dbd4f9
5
5
  SHA512:
6
- metadata.gz: 6d226a63c03330548194f7f0783873ea1b4468084f8655a629b36dc786b2a6f447cef0b56d6c3121c61ee62271de049c8846bcc406ab5523f42d62d37288d272
7
- data.tar.gz: 92c3514964ad7b19fd31f0b5bef62dddb4f45a69face9446bb758c3ea0612cace7e466b3481736f1a4b635d06f63c894a1c6d0d1843050d88170f9114783ea84
6
+ metadata.gz: 5221720bceac61c7ab85c82723daf410edde7074c75727796caab89fb4df6af501bbaad7db6e78cb15a6afda97f2be33d8d93edc19fb6951dc104f0db4d036a8
7
+ data.tar.gz: ebac93fa3b2b241525b270e6512b3b9acfaa78e6551718dd6f9cf756a34d7bdce982457a1d34684c3ecc94eced0a0cade3e33c85b8ff79532dfdf1200f30e877
data/README.md CHANGED
@@ -19,8 +19,40 @@ This gem lets your API users pass in and receive camelCased or dash-cased keys,
19
19
 
20
20
  Include a `X-Key-Inflection` header with values of `camel`, `dash`, or `snake` in your JSON API requests.
21
21
 
22
+
22
23
  For more examples, see [our blog post](https://www.viget.com/articles/introducing-olivebranch).
23
24
 
25
+ ## Optimizations and configuration
26
+
27
+ `OliveBranch` uses `multi_json`, which will choose the fastest available JSON parsing library and use that. Combined with `Oj` can speed things up and save ~20% rails response time.
28
+
29
+ The middleware can be initialized with custom camelize/dasherize implementations, so if you know you have a fixed size set of keys, you can save a considerable amount of time by providing a custom camelize that caches like so:
30
+
31
+ ```ruby
32
+ class FastCamel
33
+ def self.camel_cache
34
+ @camel_cache ||= {}
35
+ end
36
+
37
+ def self.camelize(string)
38
+ camel_cache[string] ||= string.underscore.camelize(:lower)
39
+ end
40
+ end
41
+
42
+
43
+ ...
44
+
45
+ config.middleware.use OliveBranch::Middleware, camelize: FastCamel.method(:camelize)
46
+
47
+ ```
48
+
49
+ A benchmark of this compared to the standard implementation shows a saving of ~75% rails response times for a complex response payload, or a ~400% improvement, but there is a risk of memory usage ballooning if you have dynamic keys. You can make this method as complex as required, but keep in mind that it will end up being called a _lot_ in a busy app, so it's worth thinking about how to do what you need in the fastest manner possible.
50
+
51
+ It is also possible to include a custom content type check in the same manner
52
+
53
+ ```ruby
54
+ config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) { content_type == "my/content-type" }
55
+ ```
24
56
 
25
57
  * * *
26
58
 
@@ -1,51 +1,84 @@
1
+ require "multi_json"
2
+
1
3
  module OliveBranch
4
+ class Checks
5
+ def self.content_type_check(content_type)
6
+ content_type =~ /application\/json/
7
+ end
8
+ end
9
+
10
+ class Transformations
11
+ class << self
12
+ def transform(value, transform_method)
13
+ case value
14
+ when Array then value.map { |item| transform(item, transform_method) }
15
+ when Hash then value.deep_transform_keys! { |key| transform(key, transform_method) }
16
+ when String then transform_method.call(value)
17
+ else value
18
+ end
19
+ end
20
+
21
+ def camelize(string)
22
+ string.underscore.camelize(:lower)
23
+ end
24
+
25
+ def dasherize(string)
26
+ string.dasherize
27
+ end
28
+
29
+ def underscore_params(env)
30
+ req = ActionDispatch::Request.new(env)
31
+ req.request_parameters
32
+ req.query_parameters
33
+
34
+ env["action_dispatch.request.request_parameters"].deep_transform_keys!(&:underscore)
35
+ env["action_dispatch.request.query_parameters"].deep_transform_keys!(&:underscore)
36
+ end
37
+ end
38
+ end
39
+
2
40
  class Middleware
3
- def initialize(app)
41
+ def initialize(app, args = {})
4
42
  @app = app
43
+ @camelize = args[:camelize] || Transformations.method(:camelize)
44
+ @dasherize = args[:dasherize] || Transformations.method(:dasherize)
45
+ @content_type_check = args[:content_type_check] || Checks.method(:content_type_check)
5
46
  end
6
47
 
7
48
  def call(env)
8
49
  inflection = env["HTTP_X_KEY_INFLECTION"]
9
50
 
10
- if inflection && env["CONTENT_TYPE"] =~ /application\/json/
11
- underscore_params(env)
51
+ if inflection && @content_type_check.call(env["CONTENT_TYPE"])
52
+ Transformations.underscore_params(env)
12
53
  end
13
54
 
14
55
  @app.call(env).tap do |_status, headers, response|
15
- next unless inflection && headers["Content-Type"] =~ /application\/json/
56
+ next unless inflection && @content_type_check.call(headers["Content-Type"])
16
57
  response.each do |body|
17
58
  begin
18
- new_response = JSON.parse(body)
19
- rescue JSON::ParserError
59
+ new_response = MultiJson.load(body)
60
+ rescue MultiJson::ParseError
20
61
  next
21
62
  end
22
63
 
23
- if inflection == "camel"
24
- if new_response.is_a? Array
25
- new_response.each { |o| o.deep_transform_keys! { |k| k.underscore.camelize(:lower)} }
26
- else
27
- new_response.deep_transform_keys! { |k| k.underscore.camelize(:lower) }
28
- end
29
- elsif inflection == "dash"
30
- if new_response.is_a? Array
31
- new_response.each { |o| o.deep_transform_keys!(&:dasherize) }
32
- else
33
- new_response.deep_transform_keys!(&:dasherize)
34
- end
35
- end
64
+ Transformations.transform(new_response, inflection_method(inflection))
36
65
 
37
- body.replace(new_response.to_json)
66
+ body.replace(MultiJson.dump(new_response))
38
67
  end
39
68
  end
40
69
  end
41
70
 
42
- def underscore_params(env)
43
- req = ActionDispatch::Request.new(env)
44
- req.request_parameters
45
- req.query_parameters
71
+ private
46
72
 
47
- env["action_dispatch.request.request_parameters"].deep_transform_keys!(&:underscore)
48
- env["action_dispatch.request.query_parameters"].deep_transform_keys!(&:underscore)
73
+ def inflection_method(inflection)
74
+ if inflection == "camel"
75
+ @camelize
76
+ elsif inflection == "dash"
77
+ @dasherize
78
+ else
79
+ # probably misconfigured, do nothing
80
+ -> (string) { string }
81
+ end
49
82
  end
50
83
  end
51
84
  end
@@ -1,3 +1,3 @@
1
1
  module OliveBranch
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: olive_branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eli Fatsi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-07 00:00:00.000000000 Z
12
+ date: 2017-09-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -25,20 +25,90 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '4.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: multi_json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: oj
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
28
56
  - !ruby/object:Gem::Dependency
29
57
  name: rspec
30
58
  requirement: !ruby/object:Gem::Requirement
31
59
  requirements:
32
60
  - - "~>"
33
61
  - !ruby/object:Gem::Version
34
- version: '3.2'
62
+ version: 3.5.0
35
63
  type: :development
36
64
  prerelease: false
37
65
  version_requirements: !ruby/object:Gem::Requirement
38
66
  requirements:
39
67
  - - "~>"
40
68
  - !ruby/object:Gem::Version
41
- version: '3.2'
69
+ version: 3.5.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: appraisal
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec-rails
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: sqlite3
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
42
112
  description: Handle camel/snake/dash case conversion
43
113
  email:
44
114
  - eli.fatsi@viget.com