olive_branch 2.1.2 → 4.0.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
- SHA1:
3
- metadata.gz: af62cb65fbea81bf6ad9a11e59412a2b8a834c94
4
- data.tar.gz: 716f051af8d506fb0ebd1d9091c532654209baf6
2
+ SHA256:
3
+ metadata.gz: 3bec73b70112a823836210ff185bcf853dfa2d7417be60ddab5e9d2e37d59f37
4
+ data.tar.gz: 8c494c373619e9543d0ccb28bbafe3664edc32d3a975a220c052a9422fce916e
5
5
  SHA512:
6
- metadata.gz: 833e3fb79c0f420ab19feb5b58b5b696671e755ced9d1c52556be334e4f2f0a1345118cede1fb18f1cd77a3c75e9b2a1a097b246362b996d6335649e4ee105a3
7
- data.tar.gz: 775099adb481be8ab774b68e2a8eb1abeb01e7084304d879df953d6616d637701e35f1b15afa3b96ceb3085531f24630041ddf84f4ed11de963367f6ddbb7535
6
+ metadata.gz: 2ca6f8224a09fa9113a6e6c0caa45cb928f2eba5ed2538a06e2726d931892af3a31e31c1ca7fb90cec95e7392a5a3cc9a21b8be9427f0af4b50ee3f73672bc86
7
+ data.tar.gz: b949f436070efe153eb34c11b9677a0f86b8999406630753cc726de5387d5d266b856afd30c028e24df733c93669a673d4919ca922c91517cc9f9bca8f31c628
data/README.md CHANGED
@@ -9,22 +9,38 @@ This gem lets your API users pass in and receive camelCased or dash-cased keys,
9
9
 
10
10
  1. Add this to your Gemfile and then `bundle install`:
11
11
 
12
- gem "olive_branch"
12
+ ```ruby
13
+ gem "olive_branch"
14
+ ```
13
15
 
14
- 2. Add this to `config/applcation.rb`:
16
+ 2. Add this to `config/applcation.rb` if you want the clients to control the transformation behaviour through the `Key-Inflection` HTTP header sent by the client:
15
17
 
16
- config.middleware.use OliveBranch::Middleware
18
+ ```ruby
19
+ config.middleware.use OliveBranch::Middleware
20
+ ```
17
21
 
18
- ## Use
22
+ Alternative, if you want to always convert between snake_case and camelCase for your API and only your API, to keep Rubyist and JavaScript developer's happy, use the following configuration:
19
23
 
20
- Include a `X-Key-Inflection` header with values of `camel`, `dash`, or `snake` in your JSON API requests.
24
+ ```ruby
25
+ excluded_routes = ->(env) { !env["PATH_INFO"].match(%r{^/api}) }
26
+ config.middleware.use OliveBranch::Middleware,
27
+ inflection: "camel",
28
+ exclude_params: excluded_routes,
29
+ exclude_response: excluded_routes
30
+ ```
21
31
 
32
+ in your `config/application.rb`.
33
+
34
+ ## Use
35
+
36
+ Include a `Key-Inflection` header with values of `camel`, `dash`, `snake` or `pascal` in your JSON API requests.
22
37
 
23
38
  For more examples, see [our blog post](https://www.viget.com/articles/introducing-olivebranch).
24
39
 
25
40
  ## Optimizations and configuration
26
41
 
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.
42
+ `OliveBranch` uses `multi_json`, which will automatically choose the fastest available JSON parsing library present in your application.
43
+ Most Ruby applications default to using the JSON library that ships with Ruby. However, by including a coder that `multi_json` considers faster, like [Oj](https://github.com/ohler55/oj) in your gemfile, you can potentially save up to ~20% response time.
28
44
 
29
45
  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
46
 
@@ -42,14 +58,19 @@ end
42
58
 
43
59
  ...
44
60
 
45
- config.middleware.use OliveBranch::Middleware, camelize: FastCamel.method(:camelize)
61
+ config.middleware.use OliveBranch::Middleware, camelize: FastCamel.method(:camelize)
62
+ ```
63
+
64
+ Default inflection header key can be changed like
46
65
 
66
+ ```ruby
67
+ config.middleware.use OliveBranch::Middleware, inflection_header: 'Inflect-With'
47
68
  ```
48
69
 
49
- A default inflection can be specified so you don't have to include the `X-Key-Inflection` header on every request.
70
+ A default inflection can be specified so you don't have to include the `Key-Inflection` header on every request. If you opt for default inflection, you may want to exclude the routes that Rails uses (see Filtering).
50
71
 
51
72
  ```ruby
52
- config.middleware.use OliveBranch::Middleware, inflection: 'camel'
73
+ config.middleware.use OliveBranch::Middleware, inflection: 'camel'
53
74
  ```
54
75
 
55
76
  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.
@@ -61,7 +82,9 @@ A benchmark of this compared to the standard implementation shows a saving of ~7
61
82
  It is also possible to include a custom content type check in the same manner
62
83
 
63
84
  ```ruby
64
- config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) { content_type == "my/content-type" }
85
+ config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) {
86
+ content_type == "my/content-type"
87
+ }
65
88
  ```
66
89
 
67
90
  #### Excluding URLs
@@ -71,13 +94,41 @@ Additionally you can define a custom check by passing a proc
71
94
  For params transforming
72
95
 
73
96
  ```ruby
74
- config.middleware.use OliveBranch::Middleware, exclude_params: -> (env) { env['PATH_INFO'].match(/^\/do_not_transform/) }
97
+ config.middleware.use OliveBranch::Middleware, exclude_params: -> (env) {
98
+ env['PATH_INFO'].match(/^\/do_not_transform/)
99
+ }
75
100
  ```
76
101
 
77
102
  Or response transforming
78
103
 
79
104
  ```ruby
80
- config.middleware.use OliveBranch::Middleware, exclude_response: -> (env) { env['PATH_INFO'].match(/^\/do_not_transform/) }
105
+ config.middleware.use OliveBranch::Middleware, exclude_response: -> (env) {
106
+ env['PATH_INFO'].match(/^\/do_not_transform/)
107
+ }
108
+ ```
109
+
110
+ #### Rails routes & Action Text
111
+
112
+ If you're using default inflection, exclude the routes that Rails uses
113
+ ```ruby
114
+ rails_routes = -> (env) { env['PATH_INFO'].match(/^\/rails/) }
115
+ config.middleware.use OliveBranch::Middleware, inflection: "camel", exclude_params: rails_routes, exclude_response: rails_routes
116
+ ```
117
+
118
+ ## Upgrading to version 3
119
+
120
+ Default inflection header changed from `X-Key-Inflection` to `Key-Inflection`.
121
+
122
+ ## Troubleshooting
123
+
124
+ We've seen folks raise issues that inbound transformations are not taking place. This is often due to the fact that OliveBranch, by default, is only transforming keys when a request's Content-Type is `application/json`.
125
+
126
+ Note that your HTTP client library may suppress even a manually specified `Content-Type` header if the request body is empty (e.g. [Axios does this](https://github.com/axios/axios/issues/86)). This is a common gotcha for GET requests, the body of which are [often expected to be empty](https://stackoverflow.com/questions/978061/http-get-with-request-body) for reasons of caching. If you're seeing the middleware perform on POST or PATCH requests, but not GET requests, this may be your issue.
127
+
128
+ You may choose to force inbound transformation on every request by overriding the `content_type_check` functionality:
129
+
130
+ ```ruby
131
+ config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) { true }
81
132
  ```
82
133
 
83
134
  * * *
@@ -3,7 +3,7 @@ require "multi_json"
3
3
  module OliveBranch
4
4
  class Checks
5
5
  def self.content_type_check(content_type)
6
- content_type =~ /application\/json/
6
+ content_type =~ /application\/json/ || content_type =~ /application\/vnd\.api\+json/
7
7
  end
8
8
 
9
9
  def self.default_exclude(env)
@@ -22,6 +22,10 @@ module OliveBranch
22
22
  end
23
23
  end
24
24
 
25
+ def pascalize(string)
26
+ string.underscore.camelize(:upper)
27
+ end
28
+
25
29
  def camelize(string)
26
30
  string.underscore.camelize(:lower)
27
31
  end
@@ -46,30 +50,37 @@ module OliveBranch
46
50
  @app = app
47
51
  @camelize = args[:camelize] || Transformations.method(:camelize)
48
52
  @dasherize = args[:dasherize] || Transformations.method(:dasherize)
53
+ @pascalize = args[:pascalize] || Transformations.method(:pascalize)
49
54
  @content_type_check = args[:content_type_check] || Checks.method(:content_type_check)
50
55
  @exclude_response = args[:exclude_response] || Checks.method(:default_exclude)
51
56
  @exclude_params = args[:exclude_params] || Checks.method(:default_exclude)
52
57
  @default_inflection = args[:inflection]
58
+ @inflection_header = args.fetch(:inflection_header, 'Key-Inflection').gsub(/[^a-z0-9]/i, '_').upcase
59
+ @inflection_header = "HTTP_#{@inflection_header}" unless @inflection_header.start_with?('HTTP_')
53
60
  end
54
61
 
55
62
  def call(env)
56
63
  Transformations.underscore_params(env) unless exclude_params?(env)
64
+ status, headers, response = @app.call(env)
57
65
 
58
- @app.call(env).tap do |_status, headers, response|
59
- next if exclude_response?(env, headers)
60
-
61
- response.each do |body|
62
- begin
63
- new_response = MultiJson.load(body)
64
- rescue MultiJson::ParseError
65
- next
66
- end
66
+ return [status, headers, response] if exclude_response?(env, headers)
67
67
 
68
- Transformations.transform(new_response, inflection_method(env))
68
+ new_responses = []
69
69
 
70
- body.replace(MultiJson.dump(new_response))
70
+ response.each do |body|
71
+ begin
72
+ new_response = MultiJson.load(body)
73
+ rescue MultiJson::ParseError
74
+ new_responses << body
75
+ next
71
76
  end
77
+
78
+ Transformations.transform(new_response, inflection_method(env))
79
+
80
+ new_responses << MultiJson.dump(new_response)
72
81
  end
82
+
83
+ [status, headers, new_responses]
73
84
  end
74
85
 
75
86
  private
@@ -91,7 +102,7 @@ module OliveBranch
91
102
  end
92
103
 
93
104
  def inflection_type(env)
94
- env["HTTP_X_KEY_INFLECTION"] || @default_inflection
105
+ env[@inflection_header] || @default_inflection
95
106
  end
96
107
 
97
108
  def inflection_method(env)
@@ -101,6 +112,8 @@ module OliveBranch
101
112
  @camelize
102
113
  elsif inflection == "dash"
103
114
  @dasherize
115
+ elsif inflection == 'pascal'
116
+ @pascalize
104
117
  else
105
118
  # probably misconfigured, do nothing
106
119
  -> (string) { string }
@@ -1,3 +1,3 @@
1
1
  module OliveBranch
2
- VERSION = '2.1.2'
2
+ VERSION = '4.0.0'
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: olive_branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eli Fatsi
8
8
  - David Eisinger
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-01-29 00:00:00.000000000 Z
12
+ date: 2021-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -39,20 +39,6 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
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'
56
42
  - !ruby/object:Gem::Dependency
57
43
  name: rspec
58
44
  requirement: !ruby/object:Gem::Requirement
@@ -95,20 +81,6 @@ dependencies:
95
81
  - - ">="
96
82
  - !ruby/object:Gem::Version
97
83
  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'
112
84
  description: Handle camel/snake/dash case conversion
113
85
  email:
114
86
  - eli.fatsi@viget.com
@@ -126,7 +98,7 @@ homepage: https://github.com/vigetlabs/olive_branch
126
98
  licenses:
127
99
  - MIT
128
100
  metadata: {}
129
- post_install_message:
101
+ post_install_message:
130
102
  rdoc_options: []
131
103
  require_paths:
132
104
  - lib
@@ -141,9 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
113
  - !ruby/object:Gem::Version
142
114
  version: '0'
143
115
  requirements: []
144
- rubyforge_project:
145
- rubygems_version: 2.5.1
146
- signing_key:
116
+ rubygems_version: 3.0.1
117
+ signing_key:
147
118
  specification_version: 4
148
119
  summary: Handle camel/snake/dash case conversion
149
120
  test_files: []