lhs 26.0.0 → 26.2.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 +4 -4
- data/README.md +14 -14
- data/lhs.gemspec +1 -1
- data/lib/lhs/concerns/item/save.rb +1 -1
- data/lib/lhs/concerns/record/request.rb +9 -1
- data/lib/lhs/interceptors/auto_oauth/interceptor.rb +1 -1
- data/lib/lhs/version.rb +1 -1
- data/spec/auto_oauth_spec.rb +41 -0
- data/spec/dummy/app/controllers/automatic_authentication_controller.rb +7 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/item/save_spec.rb +10 -0
- data/spec/record/includes_after_expansion_spec.rb +47 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22e5b204d979d2ed46eb93ce3ff08b6eb0aea9576f2509c7ff0c83f3c3835f75
|
4
|
+
data.tar.gz: 8ce212c4ad06e810bf0911f0a9fdc4e86afe434c00cfca2d3cdaaf4b5e4e1ba9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 377c21cf804980cd3eb2ceaaac9a1bff0a68dce97fc6c92cdf15370808bb1b161cac99b20ffb94eda901ed11ed17fefac3eda74eca54c1249c837baf8ef8e1e8
|
7
|
+
data.tar.gz: 8a9f39abe3ee1f969d0397099d219fde3eb80278299d0ea9d44938726310b7b1025220e1a715793c787661c44219b62b17aa759cefc2bcc07fbea75b94a99447
|
data/README.md
CHANGED
@@ -171,7 +171,7 @@ record.review # "Lunch was great
|
|
171
171
|
|
172
172
|
### Endpoints
|
173
173
|
|
174
|
-
> Endpoint, the entry point to a service, a process,
|
174
|
+
> Endpoint, the entry point to a service, a process, a queue or a topic in a service-oriented architecture
|
175
175
|
|
176
176
|
Start a record with configuring one or multiple endpoints.
|
177
177
|
|
@@ -251,7 +251,7 @@ end
|
|
251
251
|
|
252
252
|
#### Endpoint Priorities
|
253
253
|
|
254
|
-
LHS uses endpoint configurations to determine what endpoint to use when data is requested, in a
|
254
|
+
LHS uses endpoint configurations to determine what endpoint to use when data is requested, in a similar way, routes are identified in Rails to map requests to controllers.
|
255
255
|
|
256
256
|
If they are ambiguous, LHS will always use the first one found:
|
257
257
|
|
@@ -275,7 +275,7 @@ Record.fetch
|
|
275
275
|
GET https://service.example.com/records
|
276
276
|
```
|
277
277
|
|
278
|
-
**Be aware that, if you configure
|
278
|
+
**Be aware that, if you configure ambiguous endpoints across multiple classes, the order of things is not deterministic. Ambiguous endpoints across multiple classes need to be avoided.**
|
279
279
|
|
280
280
|
### Provider
|
281
281
|
|
@@ -479,7 +479,7 @@ The different behavior of `count` and `length` is based on ActiveRecord's behavi
|
|
479
479
|
|
480
480
|
`count` The total number of items available remotly via the provided endpoint/api, communicated via pagination meta data.
|
481
481
|
|
482
|
-
`length` The number of items already loaded from the endpoint/api and kept in
|
482
|
+
`length` The number of items already loaded from the endpoint/api and kept in memory right now. In case of a paginated endpoint this can differ to what `count` returns, as it depends on how many pages have been loaded already.
|
483
483
|
|
484
484
|
### Find single records
|
485
485
|
|
@@ -593,7 +593,7 @@ How to configure endpoints for automatic collection detection?
|
|
593
593
|
|
594
594
|
LHS detects automatically if the responded data is a single business object or a set of business objects (collection).
|
595
595
|
|
596
|
-
Conventionally, when the
|
596
|
+
Conventionally, when the respons contains an `items` key `{ items: [] }` it's treated as a collection, but also if the respons contains a plain raw array: `[{ href: '' }]` it's also treated as a collection.
|
597
597
|
|
598
598
|
If you need to configure the attribute of the response providing the collection, configure `items_key` as explained here: [Determine collections from the response body](#determine-collections-from-the-response-body)
|
599
599
|
|
@@ -782,7 +782,7 @@ end
|
|
782
782
|
|
783
783
|
#### Unwrap nested items from the response body
|
784
784
|
|
785
|
-
If the actual item data is mixed with
|
785
|
+
If the actual item data is mixed with metadata in the response body, LHS allows you to configure a record in a way to automatically unwrap items from within nested response data.
|
786
786
|
|
787
787
|
`item_key` is used to unwrap the actual object from within the response body.
|
788
788
|
|
@@ -1058,7 +1058,7 @@ records = Record.where(color: 'blue').fetch
|
|
1058
1058
|
|
1059
1059
|
#### Add request options to a query chain: options
|
1060
1060
|
|
1061
|
-
You can apply options to the request chain. Those options will be forwarded to the request
|
1061
|
+
You can apply options to the request chain. Those options will be forwarded to the request performed by the chain/query:
|
1062
1062
|
|
1063
1063
|
```ruby
|
1064
1064
|
# app/controllers/some_controller.rb
|
@@ -1178,7 +1178,7 @@ Record.page(3).per(20).where(color: 'blue')
|
|
1178
1178
|
GET https://service.example.com/records?offset=40&limit=20&color=blue
|
1179
1179
|
```
|
1180
1180
|
|
1181
|
-
The applied pagination strategy depends on
|
1181
|
+
The applied pagination strategy depends on what's configured for the particular record: See [Record pagination](#record-pagination)
|
1182
1182
|
|
1183
1183
|
### Record pagination
|
1184
1184
|
|
@@ -1330,7 +1330,7 @@ Sequentially:
|
|
1330
1330
|
##### limit_key
|
1331
1331
|
|
1332
1332
|
`limit_key` sets the key used to indicate how many items you want to retrieve per page e.g. `size`, `limit`, etc.
|
1333
|
-
In case the `limit_key` parameter differs for how it needs to be requested from how it's provided in the
|
1333
|
+
In case the `limit_key` parameter differs for how it needs to be requested from how it's provided in the response, use `body` and `parameter` subkeys.
|
1334
1334
|
|
1335
1335
|
```ruby
|
1336
1336
|
# app/models/record.rb
|
@@ -1359,7 +1359,7 @@ GET https://service.example.com/records?color=blue&max=100
|
|
1359
1359
|
##### pagination_key
|
1360
1360
|
|
1361
1361
|
`pagination_key` defines which key to use to paginate a page (e.g. `offset`, `page`, `startAt` etc.).
|
1362
|
-
In case the `limit_key` parameter differs for how it needs to be requested from how it's provided in the
|
1362
|
+
In case the `limit_key` parameter differs for how it needs to be requested from how it's provided in the response, use `body` and `parameter` subkeys.
|
1363
1363
|
|
1364
1364
|
```ruby
|
1365
1365
|
# app/models/record.rb
|
@@ -1584,7 +1584,7 @@ POST https://service.example.com/records { body: "{ 'name' : 'Starbucks' }" }
|
|
1584
1584
|
|
1585
1585
|
##### save
|
1586
1586
|
|
1587
|
-
`save` persist the whole object in
|
1587
|
+
`save` persist the whole object in its current state.
|
1588
1588
|
|
1589
1589
|
`save` will return `false` if persisting fails. `save!` instead will raise an exception.
|
1590
1590
|
|
@@ -2023,7 +2023,7 @@ DELETE https://service.example.com/records?name='Steve'
|
|
2023
2023
|
|
2024
2024
|
### Record getters and setters
|
2025
2025
|
|
2026
|
-
Sometimes it is
|
2026
|
+
Sometimes it is necessary to implement custom getters and setters and convert data to a processable (endpoint) format behind the scenes.
|
2027
2027
|
|
2028
2028
|
#### Record setters
|
2029
2029
|
|
@@ -2201,7 +2201,7 @@ customer.contracts.first.products.first.name # Local Business Card
|
|
2201
2201
|
|
2202
2202
|
#### Include various levels of linked data
|
2203
2203
|
|
2204
|
-
The method syntax of `includes` allows you include hyperlinks stored in deep nested data
|
2204
|
+
The method syntax of `includes` allows you to include hyperlinks stored in deep nested data structures:
|
2205
2205
|
|
2206
2206
|
Some examples:
|
2207
2207
|
|
@@ -2283,7 +2283,7 @@ In parallel:
|
|
2283
2283
|
GET https://service.example.com/places/4 { headers: { 'Authentication': 'Bearer 123' } }
|
2284
2284
|
```
|
2285
2285
|
|
2286
|
-
Here is another example, if you want to ignore errors, that
|
2286
|
+
Here is another example, if you want to ignore errors, that occur while you fetch included resources:
|
2287
2287
|
|
2288
2288
|
```ruby
|
2289
2289
|
# app/controllers/some_controller.rb
|
data/lhs.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_development_dependency 'json', '>= 1.8.2'
|
32
32
|
s.add_development_dependency 'pry'
|
33
33
|
s.add_development_dependency 'pry-byebug'
|
34
|
-
s.add_development_dependency 'rails', '>= 4.2.11'
|
34
|
+
s.add_development_dependency 'rails', '>= 4.2.11', '< 7'
|
35
35
|
s.add_development_dependency 'rollbar', '<= 2.24.0'
|
36
36
|
s.add_development_dependency 'rspec-rails', '>= 3.7.0'
|
37
37
|
s.add_development_dependency 'rubocop', '~> 0.57.1'
|
@@ -34,7 +34,7 @@ class LHS::Item < LHS::Proxy
|
|
34
34
|
private
|
35
35
|
|
36
36
|
def apply_default_creation_options(options, url, data)
|
37
|
-
options = options.merge(method: :post, url: url, body: data)
|
37
|
+
options = options.merge(method: options.fetch(:method, :post), url: url, body: data)
|
38
38
|
options[:headers] ||= {}
|
39
39
|
options
|
40
40
|
end
|
@@ -123,7 +123,15 @@ class LHS::Record
|
|
123
123
|
options = extend_with_reference(options, reference)
|
124
124
|
addition = load_existing_includes(options, data, sub_includes, reference)
|
125
125
|
data.extend!(addition, included)
|
126
|
-
|
126
|
+
unless expanded_data?(addition)
|
127
|
+
if data.collection?
|
128
|
+
data.each do |item|
|
129
|
+
expand_addition!(item, included, reference)
|
130
|
+
end
|
131
|
+
else
|
132
|
+
expand_addition!(data, included, reference)
|
133
|
+
end
|
134
|
+
end
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
data/lib/lhs/version.rb
CHANGED
data/spec/auto_oauth_spec.rb
CHANGED
@@ -165,5 +165,46 @@ describe 'Auto OAuth Authentication', type: :request, dummy_models: true do
|
|
165
165
|
expect(records_request).to have_been_requested
|
166
166
|
end
|
167
167
|
end
|
168
|
+
|
169
|
+
context 'overriding auth options with provider enabled for auto oauth' do
|
170
|
+
|
171
|
+
let(:token) { ApplicationController::ACCESS_TOKEN }
|
172
|
+
let(:overridden_token) { 'ACCESS_TOKEN' }
|
173
|
+
|
174
|
+
let(:record_request) do
|
175
|
+
stub_request(:get, "http://internalservice/v2/records/1")
|
176
|
+
.with(
|
177
|
+
headers: { 'Authorization' => "Bearer #{overridden_token}" }
|
178
|
+
).to_return(status: 200, body: { name: 'Record' }.to_json)
|
179
|
+
end
|
180
|
+
|
181
|
+
let(:records_request) do
|
182
|
+
stub_request(:get, "http://internalservice/v2/records?color=blue")
|
183
|
+
.with(
|
184
|
+
headers: { 'Authorization' => "Bearer #{overridden_token}" }
|
185
|
+
).to_return(status: 200, body: { items: [{ name: 'Record' }] }.to_json)
|
186
|
+
end
|
187
|
+
|
188
|
+
before do
|
189
|
+
LHS.configure do |config|
|
190
|
+
config.auto_oauth = -> { access_token }
|
191
|
+
end
|
192
|
+
LHC.configure do |config|
|
193
|
+
config.interceptors = [LHC::Auth]
|
194
|
+
end
|
195
|
+
record_request
|
196
|
+
records_request
|
197
|
+
end
|
198
|
+
|
199
|
+
after do
|
200
|
+
LHC.config.reset
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'applies OAuth credentials for the individual request automatically' do
|
204
|
+
get '/automatic_authentication/oauth_with_provider_override', params: { access_token: overridden_token }
|
205
|
+
expect(record_request).to have_been_requested
|
206
|
+
expect(records_request).to have_been_requested
|
207
|
+
end
|
208
|
+
end
|
168
209
|
end
|
169
210
|
end
|
@@ -26,4 +26,11 @@ class AutomaticAuthenticationController < ApplicationController
|
|
26
26
|
records: DummyRecordWithAutoOauthProvider.where(color: 'blue').as_json
|
27
27
|
}
|
28
28
|
end
|
29
|
+
|
30
|
+
def o_auth_with_provider_override
|
31
|
+
render json: {
|
32
|
+
record: DummyRecordWithAutoOauthProvider.options(auth: { bearer: params[:access_token] }).find(1).as_json,
|
33
|
+
records: DummyRecordWithAutoOauthProvider.options(auth: { bearer: params[:access_token] }).where(color: 'blue').as_json
|
34
|
+
}
|
35
|
+
end
|
29
36
|
end
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -7,6 +7,7 @@ Rails.application.routes.draw do
|
|
7
7
|
get 'automatic_authentication/oauth' => 'automatic_authentication#o_auth'
|
8
8
|
get 'automatic_authentication/oauth_with_multiple_providers' => 'automatic_authentication#o_auth_with_multiple_providers'
|
9
9
|
get 'automatic_authentication/oauth_with_provider' => 'automatic_authentication#o_auth_with_provider'
|
10
|
+
get 'automatic_authentication/oauth_with_provider_override' => 'automatic_authentication#o_auth_with_provider_override'
|
10
11
|
|
11
12
|
# Request Cycle Cache
|
12
13
|
get 'request_cycle_cache/simple' => 'request_cycle_cache#simple'
|
data/spec/item/save_spec.rb
CHANGED
@@ -112,4 +112,14 @@ describe LHS::Item do
|
|
112
112
|
expect(request).to have_been_requested
|
113
113
|
end
|
114
114
|
end
|
115
|
+
|
116
|
+
context 'chainable' do
|
117
|
+
it 'allows to chain save with options' do
|
118
|
+
stub_request(:put, item.href).with(body: item._raw.merge(name: 'Steve').to_json)
|
119
|
+
item.name = 'Steve'
|
120
|
+
result = item.options(method: :put).save
|
121
|
+
|
122
|
+
expect(result).to eq true
|
123
|
+
end
|
124
|
+
end
|
115
125
|
end
|
@@ -69,4 +69,51 @@ describe LHS::Record do
|
|
69
69
|
).to eq 'OPL'
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
context 'with collections' do
|
74
|
+
before do
|
75
|
+
class User < LHS::Record
|
76
|
+
endpoint 'http://users'
|
77
|
+
endpoint 'http://users/{id}'
|
78
|
+
end
|
79
|
+
|
80
|
+
class Places < LHS::Record
|
81
|
+
endpoint 'http://users/{id}/places'
|
82
|
+
endpoint 'http://places/{id}'
|
83
|
+
end
|
84
|
+
|
85
|
+
stub_request(:get, 'http://users?email=user@example.com')
|
86
|
+
.to_return(
|
87
|
+
body: {
|
88
|
+
href: 'http://users?email=user@example.com',
|
89
|
+
items: [
|
90
|
+
{
|
91
|
+
places: {
|
92
|
+
href: 'http://users/1/places'
|
93
|
+
}
|
94
|
+
}
|
95
|
+
]
|
96
|
+
}.to_json
|
97
|
+
)
|
98
|
+
|
99
|
+
stub_request(:get, 'http://users/1/places?limit=100')
|
100
|
+
.to_return(
|
101
|
+
body: {
|
102
|
+
items: [
|
103
|
+
{
|
104
|
+
title: 'Place'
|
105
|
+
}
|
106
|
+
],
|
107
|
+
total: 0,
|
108
|
+
offset: 0,
|
109
|
+
limit: 10
|
110
|
+
}.to_json
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'includes resources after expanding plain links' do
|
115
|
+
user = User.includes(:places).find(email: 'user@example.com')
|
116
|
+
expect(user.places.first.title).to eq 'Place'
|
117
|
+
end
|
118
|
+
end
|
72
119
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 26.
|
4
|
+
version: 26.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -135,6 +135,9 @@ dependencies:
|
|
135
135
|
- - ">="
|
136
136
|
- !ruby/object:Gem::Version
|
137
137
|
version: 4.2.11
|
138
|
+
- - "<"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '7'
|
138
141
|
type: :development
|
139
142
|
prerelease: false
|
140
143
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -142,6 +145,9 @@ dependencies:
|
|
142
145
|
- - ">="
|
143
146
|
- !ruby/object:Gem::Version
|
144
147
|
version: 4.2.11
|
148
|
+
- - "<"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '7'
|
145
151
|
- !ruby/object:Gem::Dependency
|
146
152
|
name: rollbar
|
147
153
|
requirement: !ruby/object:Gem::Requirement
|
@@ -564,7 +570,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
564
570
|
version: '0'
|
565
571
|
requirements:
|
566
572
|
- Ruby >= 2.3.0
|
567
|
-
rubygems_version: 3.
|
573
|
+
rubygems_version: 3.1.4
|
568
574
|
signing_key:
|
569
575
|
specification_version: 4
|
570
576
|
summary: 'REST services accelerator: Rails gem providing an easy, active-record-like
|