olive_branch 2.1.2 → 4.0.0
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 +5 -5
- data/README.md +63 -12
- data/lib/olive_branch/middleware.rb +26 -13
- data/lib/olive_branch/version.rb +1 -1
- metadata +6 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3bec73b70112a823836210ff185bcf853dfa2d7417be60ddab5e9d2e37d59f37
|
4
|
+
data.tar.gz: 8c494c373619e9543d0ccb28bbafe3664edc32d3a975a220c052a9422fce916e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
18
|
+
```ruby
|
19
|
+
config.middleware.use OliveBranch::Middleware
|
20
|
+
```
|
17
21
|
|
18
|
-
|
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
|
-
|
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
|
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
|
-
|
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 `
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
68
|
+
new_responses = []
|
69
69
|
|
70
|
-
|
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[
|
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 }
|
data/lib/olive_branch/version.rb
CHANGED
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:
|
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:
|
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
|
-
|
145
|
-
|
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: []
|