barkibu-kb 0.16.1
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/.env.example +3 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.rubocop.yml +45 -0
- data/.ruby-version +2 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +185 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +182 -0
- data/LICENSE.txt +21 -0
- data/README.md +243 -0
- data/Rakefile +28 -0
- data/barkibu-kb-fake.gemspec +41 -0
- data/barkibu-kb.gemspec +54 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docker-compose.yaml +15 -0
- data/lib/barkibu-kb-fake.rb +1 -0
- data/lib/barkibu-kb.rb +33 -0
- data/lib/kb/cache.rb +23 -0
- data/lib/kb/client.rb +85 -0
- data/lib/kb/client_resolver.rb +62 -0
- data/lib/kb/concerns/as_kb_wrapper.rb +67 -0
- data/lib/kb/concerns.rb +1 -0
- data/lib/kb/errors/client_error.rb +9 -0
- data/lib/kb/errors/conflict_error.rb +3 -0
- data/lib/kb/errors/error.rb +26 -0
- data/lib/kb/errors/resource_not_found.rb +3 -0
- data/lib/kb/errors/unprocessable_entity_error.rb +3 -0
- data/lib/kb/errors.rb +6 -0
- data/lib/kb/fake/api.rb +72 -0
- data/lib/kb/fake/bounded_context/pet_family/breeds.rb +15 -0
- data/lib/kb/fake/bounded_context/pet_family/hubspot_relationship.rb +17 -0
- data/lib/kb/fake/bounded_context/pet_family/pet_contracts.rb +24 -0
- data/lib/kb/fake/bounded_context/pet_family/pet_parents.rb +98 -0
- data/lib/kb/fake/bounded_context/pet_family/pets.rb +84 -0
- data/lib/kb/fake/bounded_context/pet_family/products.rb +28 -0
- data/lib/kb/fake/bounded_context/rest_resource.rb +134 -0
- data/lib/kb/fake.rb +6 -0
- data/lib/kb/inflections.rb +3 -0
- data/lib/kb/models/assessment.rb +58 -0
- data/lib/kb/models/base_model.rb +40 -0
- data/lib/kb/models/breed.rb +39 -0
- data/lib/kb/models/concerns/creatable.rb +18 -0
- data/lib/kb/models/concerns/destroyable.rb +17 -0
- data/lib/kb/models/concerns/find_or_creatable.rb +19 -0
- data/lib/kb/models/concerns/findable.rb +19 -0
- data/lib/kb/models/concerns/inspectionable.rb +13 -0
- data/lib/kb/models/concerns/listable.rb +21 -0
- data/lib/kb/models/concerns/queryable.rb +34 -0
- data/lib/kb/models/concerns/updatable.rb +18 -0
- data/lib/kb/models/concerns/upsertable.rb +17 -0
- data/lib/kb/models/concerns.rb +10 -0
- data/lib/kb/models/condition.rb +32 -0
- data/lib/kb/models/hubspot_relationship.rb +34 -0
- data/lib/kb/models/pet.rb +68 -0
- data/lib/kb/models/pet_contract.rb +77 -0
- data/lib/kb/models/pet_parent.rb +111 -0
- data/lib/kb/models/plan.rb +44 -0
- data/lib/kb/models/product.rb +34 -0
- data/lib/kb/models/symptom.rb +25 -0
- data/lib/kb/models.rb +15 -0
- data/lib/kb/type/array_of_conditions_type.rb +13 -0
- data/lib/kb/type/array_of_strings_type.rb +9 -0
- data/lib/kb/type/array_of_symptoms_type.rb +13 -0
- data/lib/kb/types.rb +7 -0
- data/lib/kb/validators/uniqueness_validator.rb +26 -0
- data/lib/kb/validators.rb +1 -0
- data/lib/kb/version.rb +3 -0
- metadata +325 -0
data/README.md
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
# Barkibu's Knowledge Base API sdk
|
2
|
+
|
3
|
+
A wrapper of Barkibu's Knowledge Base Endpoint to make those entities and their respective CRUD operations available to a ruby app.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'barkibu-kb'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install kb
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
This gem wraps the Knowledge Base Api and exposes CRUD-_able_ entities into the requiring application.
|
24
|
+
|
25
|
+
### Configuration
|
26
|
+
|
27
|
+
The configuration of the connection to the Knowledge Base is done using ENV variable:
|
28
|
+
|
29
|
+
- **KB_API_KEY**: the Knowledge Base API Key
|
30
|
+
- **KB_PARTNER_KEY**: the Partner KB Key
|
31
|
+
- **KB_API_URL_TEMPLATE**: the template url of the Knowledge Base where will be extrapolated _bounded_context_, _version_ and _entity_.
|
32
|
+
|
33
|
+
For instance: `https://dev.api.%{bounded_context}.barkkb.com/%{version}/%{entity}`.
|
34
|
+
|
35
|
+
#### Cache configuration
|
36
|
+
|
37
|
+
We add the ability to cache GET responses. To enable it, just set KB.config.cache properties:
|
38
|
+
```ruby
|
39
|
+
# config/initializers/kb_ruby.rb
|
40
|
+
KB.config.cache.instance = Rails.cache # ActiveSupport::Cache::NullStore.new
|
41
|
+
KB.config.cache.expires_in = 1.second # 0 by default
|
42
|
+
KB.config.log_level = :debugger # :info by default
|
43
|
+
```
|
44
|
+
|
45
|
+
### Exposed Entities
|
46
|
+
|
47
|
+
#### Pet Parent 🧍🏾
|
48
|
+
|
49
|
+
`KB::PetParent` acts almost like an `ActiveRecord` implementing `ActiveModel::Model` exposing:
|
50
|
+
|
51
|
+
- `find`
|
52
|
+
- arg: `key` string
|
53
|
+
- returns: a PetParent instance when provided an existing key or raise `ActiveRecord::RecordNotFound`
|
54
|
+
- `create`
|
55
|
+
- arg: `attributes` to initialize the entity
|
56
|
+
- returns: the raw attributes of the created PetParent instance
|
57
|
+
- throws an `KB::Error` exception if something went wrong
|
58
|
+
- `find_or_create_by`
|
59
|
+
- arg: `attributes`, `additional_attributes` to look for or initialize the entity
|
60
|
+
- returns: look for a PetParent matching the passed attributes or initialize and persist one with the given attributes and launching the block provided
|
61
|
+
- throws an `KB::Error` exception if something went wrong
|
62
|
+
- `all`
|
63
|
+
- arg: `filters` hash of filters
|
64
|
+
- returns: an array of PetParent instances matching the filters
|
65
|
+
- `save!`
|
66
|
+
- persists (create or update) the entity to the Knowledge Base
|
67
|
+
- throws an `KB::Error` exception if something went wrong
|
68
|
+
- `destroy!`
|
69
|
+
- deletes the entity in the Knowledge Base
|
70
|
+
- throws a `KB::Error` exception if something went wrong
|
71
|
+
- `contracts`
|
72
|
+
- returns all the KB::PetContract associated with this pet parent
|
73
|
+
|
74
|
+
#### Assessment 📄
|
75
|
+
|
76
|
+
`KB::Assessment` represents a read-only resource exposing:
|
77
|
+
|
78
|
+
- `find`
|
79
|
+
- arg: `key` string
|
80
|
+
- returns: an Assessment instance when provided an existing key or raise `ActiveRecord::RecordNotFound`
|
81
|
+
- `all`
|
82
|
+
- arg: `filters` hash of filters
|
83
|
+
- returns: an array of Assessment instances matching the filters
|
84
|
+
|
85
|
+
#### Condition 🏷
|
86
|
+
|
87
|
+
`KB::Condition` represents a read-only resource.
|
88
|
+
|
89
|
+
#### Symptom 🩺
|
90
|
+
|
91
|
+
`KB::Symptom` represents a read-only resource.
|
92
|
+
|
93
|
+
#### Pet 🐶🐱
|
94
|
+
|
95
|
+
`KB::Pet` represents a resource exposing:
|
96
|
+
|
97
|
+
- `all`
|
98
|
+
- arg: `filters` hash of filters
|
99
|
+
- returns: an array of Pet instances matching the filters
|
100
|
+
- `create`
|
101
|
+
- arg: `attributes` to initialize the entity
|
102
|
+
- returns: the raw attributes of the Pet instance
|
103
|
+
- throws an `KB::Error` exception if something went wrong
|
104
|
+
- `find_or_create_by`
|
105
|
+
- arg: `attributes`, `additional_attributes` to look for or initialize the entity
|
106
|
+
- returns: look for a Pet matching the passed attributes or initialize and persist one with the given attributes and launching the block provided
|
107
|
+
- throws an `KB::Error` exception if something went wrong
|
108
|
+
- `save!`
|
109
|
+
- persists (create or update) the entity to the Knowledge Base
|
110
|
+
- throws an `KB::Error` exception if something went wrong
|
111
|
+
- `destroy!`
|
112
|
+
- deletes the entity in the Knowledge Base
|
113
|
+
- throws a `KB::Error` exception if something went wrong
|
114
|
+
- `contracts`
|
115
|
+
- returns all the KB::PetContract associated with this pet
|
116
|
+
- `upsert`
|
117
|
+
- updates KB:Pet if exists a Pet with same name for its PetParent
|
118
|
+
- creates a new KB:Pet if not exists a Pet with same name for its PetParent
|
119
|
+
|
120
|
+
#### PetContract 📝
|
121
|
+
|
122
|
+
`KB::PetContract` represents a resource exposing:
|
123
|
+
|
124
|
+
- `find`
|
125
|
+
- arg: `key` the key of the contract in the Knowledge Base
|
126
|
+
- returns the contract with the matching key
|
127
|
+
- throws an `KB::Error` or `KB::ResourceNotFound` exception if something went wrong
|
128
|
+
- `find_by_contract_number`
|
129
|
+
- arg: `contract_number` the contract number to find
|
130
|
+
- returns the identified KB::PetContract
|
131
|
+
- throws an `KB::Error` or `KB::ResourceNotFound` exception if something went wrong
|
132
|
+
- `create`
|
133
|
+
- arg: `attributes` to initialize the entity
|
134
|
+
- returns: the raw attributes of the PetContract instance
|
135
|
+
- throws an `KB::Error` exception if something went wrong
|
136
|
+
- `save!`
|
137
|
+
- persists (create or update) the entity to the Knowledge Base
|
138
|
+
- throws an `KB::Error` exception if something went wrong
|
139
|
+
|
140
|
+
#### Plan 🗺
|
141
|
+
|
142
|
+
`KB::Plan` represents a resource exposing:
|
143
|
+
|
144
|
+
- `all`
|
145
|
+
- returns: the array of available plans
|
146
|
+
|
147
|
+
#### Breed
|
148
|
+
|
149
|
+
```
|
150
|
+
> KB Breed endpoint requires `locale` as param. By default is set to 'es-es' but can be override setting **KB_BREEDS_DEFAULT_LOCALE** ENV var
|
151
|
+
```
|
152
|
+
|
153
|
+
`KB::Breed` represents a resource exposing:
|
154
|
+
|
155
|
+
- `all`
|
156
|
+
- arg: `filters` hash of filters
|
157
|
+
- returns: and array of Breed instances matching the filters
|
158
|
+
- `dogs` (alias for all(species: 'dog'))
|
159
|
+
- arg: `filters` hash of filters
|
160
|
+
- returns: and array of Dog Breed instances matching the filters
|
161
|
+
- `cats` (alias for all(species: 'cat'))
|
162
|
+
- arg: `filters` hash of filters
|
163
|
+
- returns: and array of Cat Breed instances matching the filters
|
164
|
+
|
165
|
+
### Make an ActiveRecord wrap a KB entity
|
166
|
+
|
167
|
+
The `KB::Concerns::AsKBWrapper` concern has been created in order to easily make an ActiveRecord model wrap a KB model.
|
168
|
+
|
169
|
+
To use it:
|
170
|
+
|
171
|
+
- include it into your wrapping model, define an attribute `kb_key` on your wrapping model
|
172
|
+
- call `wrap_kb` with the wrapped KB model class (available option: `skip_callback`)
|
173
|
+
|
174
|
+
You have then access to the wrapped model under `kb_model` and can delegate attributes to it, for instance:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
class User < ActiveRecord::Base
|
178
|
+
include KB::Concerns::AsKBWrapper
|
179
|
+
|
180
|
+
wrap_kb model: KB::PetParent
|
181
|
+
|
182
|
+
KB_DELEGATED_ATTRIBUTES = %i[email first_name].freeze
|
183
|
+
|
184
|
+
KB_DELEGATED_ATTRIBUTES.each do |attribute|
|
185
|
+
delegate attribute, to: :kb_model, prefix: false
|
186
|
+
delegate "#{attribute}=", to: :kb_model, prefix: false
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
user = User.create(first_name: 'Léo', email: 'leo@barkibu.com')
|
191
|
+
p user.kb_model
|
192
|
+
# => #<KB::PetParent: 0x000055fd72d32c30 key: "373ad90e-c2ce-46cb-9749-deb2b03be995", first_name: "Léo", ..., email: "leo@barkibu.com">
|
193
|
+
```
|
194
|
+
|
195
|
+
### Mock the API calls in test environment
|
196
|
+
|
197
|
+
For testing purposes, you may want to fake Knowledge Base’s API calls. We provide a FakeApi app that you can use including the `kb-fake` gem in your dev/test dependencies.
|
198
|
+
|
199
|
+
Add gem webmock and gem sinatra to your Gemfile to use the following configuration:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
# ...
|
203
|
+
|
204
|
+
RSpec.configure do |config|
|
205
|
+
# ...
|
206
|
+
config.before(:all) do
|
207
|
+
stub_request(:any, /test_api_barkkb.com/).to_rack(KB::Fake::Api)
|
208
|
+
end
|
209
|
+
|
210
|
+
config.around(:each) do |example|
|
211
|
+
snapshot = KB::Fake::Api.snapshot()
|
212
|
+
stub_request(:any, /test_api_barkkb.com/).to_rack(KB::Fake::Api)
|
213
|
+
example.run
|
214
|
+
KB::Fake::Api.restore snapshot
|
215
|
+
end
|
216
|
+
# ...
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
Make sure to set the `KB_API_URL_TEMPLATE` to something that will match above the request interceptor, for instance: `http://test_api_barkkb.com/%{version}/%{entity}`
|
221
|
+
|
222
|
+
You should be able to use the API seemlessly and the calls to the API will be intercepted and a local one used instead in a similar fashion to how ActiveRecord operations are wrapped into a transaction in a rails app with `use_transactional_fixtures` activated.
|
223
|
+
|
224
|
+
## Development & Testing
|
225
|
+
|
226
|
+
```bash
|
227
|
+
docker run -it --rm -v $(pwd):/app --workdir=/app ruby:2.6.5 bash
|
228
|
+
|
229
|
+
> bundle install
|
230
|
+
> rspec
|
231
|
+
```
|
232
|
+
|
233
|
+
## Contributing
|
234
|
+
|
235
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/kb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
236
|
+
|
237
|
+
## License
|
238
|
+
|
239
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
240
|
+
|
241
|
+
## Code of Conduct
|
242
|
+
|
243
|
+
Everyone interacting in the KB project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/kb/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'kb/version'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
desc 'Build gem into the pkg directory'
|
9
|
+
task :build do
|
10
|
+
FileUtils.rm_rf('pkg')
|
11
|
+
Dir['*.gemspec'].each do |gemspec|
|
12
|
+
system "gem build #{gemspec}"
|
13
|
+
end
|
14
|
+
FileUtils.mkdir_p('pkg')
|
15
|
+
FileUtils.mv(Dir['*.gem'], 'pkg')
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Tags version, pushes to remote, and pushes gem'
|
19
|
+
task release: :build do
|
20
|
+
sh 'git', 'tag', '-m', changelog, "v#{KB::VERSION}"
|
21
|
+
sh 'git push origin master'
|
22
|
+
sh "git push origin v#{KB::VERSION}"
|
23
|
+
sh 'ls pkg/*.gem | xargs -n 1 gem push'
|
24
|
+
end
|
25
|
+
|
26
|
+
def changelog
|
27
|
+
File.read('CHANGELOG.md').split(/##.*$\n/)[1].gsub("\n\n", "\n")
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'kb/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'barkibu-kb-fake'
|
7
|
+
spec.version = KB::VERSION
|
8
|
+
spec.authors = ['Léo Figea']
|
9
|
+
spec.email = ['leo@barkibu.com']
|
10
|
+
|
11
|
+
spec.summary = "Barkibu's Knowledge Base Fake API"
|
12
|
+
spec.description = "A fake API of Barkibu's Knowledge Base destined to be used in tests for application using the kb-ruby gem." # rubocop:disable Layout/LineLength
|
13
|
+
spec.homepage = 'https://app.barkibu.com'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
# spec.metadata['allowed_push_host'] = 'http://mygemserver.com'
|
20
|
+
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
# spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
23
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
24
|
+
else
|
25
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
26
|
+
'public gem pushes.'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Specify which files should be added to the gem when it is released.
|
30
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
31
|
+
spec.files = `git ls-files -- lib | grep fake`.split("\n").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
|
+
spec.bindir = 'exe'
|
33
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
|
+
spec.require_paths = ['lib']
|
35
|
+
spec.required_ruby_version = '>= 2.6'
|
36
|
+
|
37
|
+
spec.add_runtime_dependency 'countries'
|
38
|
+
spec.add_runtime_dependency 'barkibu-kb', KB::VERSION
|
39
|
+
spec.add_runtime_dependency 'sinatra'
|
40
|
+
spec.add_runtime_dependency 'webmock'
|
41
|
+
end
|
data/barkibu-kb.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'kb/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'barkibu-kb'
|
7
|
+
spec.version = KB::VERSION
|
8
|
+
spec.authors = ['Léo Figea']
|
9
|
+
spec.email = ['leo@barkibu.com']
|
10
|
+
|
11
|
+
spec.summary = "Barkibu's Knowledge Base API sdk"
|
12
|
+
spec.description = "A wrapper of Barkibu's Knowledge Base Endpoint to make those entities and their respective CRUD operations available to a ruby app" # rubocop:disable Layout/LineLength
|
13
|
+
spec.homepage = 'https://app.barkibu.com'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
# spec.metadata['allowed_push_host'] = 'http://mygemserver.com'
|
20
|
+
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
# spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
23
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
24
|
+
else
|
25
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
26
|
+
'public gem pushes.'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Specify which files should be added to the gem when it is released.
|
30
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
31
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
32
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
33
|
+
end
|
34
|
+
spec.bindir = 'exe'
|
35
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
|
+
spec.require_paths = ['lib']
|
37
|
+
spec.required_ruby_version = '>= 2.6'
|
38
|
+
|
39
|
+
spec.add_dependency 'dry-configurable', '~> 0.9'
|
40
|
+
spec.add_development_dependency 'bundler', '~> 1.17'
|
41
|
+
spec.add_development_dependency 'byebug'
|
42
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
43
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
44
|
+
spec.add_development_dependency 'rubocop'
|
45
|
+
spec.add_development_dependency 'rubocop-rspec'
|
46
|
+
spec.add_development_dependency 'simplecov'
|
47
|
+
spec.add_runtime_dependency 'activemodel', '>= 4.0.2'
|
48
|
+
spec.add_runtime_dependency 'activerecord'
|
49
|
+
spec.add_runtime_dependency 'activesupport', '>= 3.0.0'
|
50
|
+
spec.add_runtime_dependency 'faraday'
|
51
|
+
spec.add_runtime_dependency 'faraday-http'
|
52
|
+
spec.add_runtime_dependency 'faraday_middleware'
|
53
|
+
spec.add_runtime_dependency 'i18n'
|
54
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'barkibu-kb'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/docker-compose.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
version: "3.0"
|
2
|
+
services:
|
3
|
+
kb:
|
4
|
+
image: ruby:2.7.1-buster
|
5
|
+
working_dir: /app
|
6
|
+
volumes:
|
7
|
+
- .:/app
|
8
|
+
- bundle:/usr/local/bundle
|
9
|
+
environment:
|
10
|
+
- KB_API_URL_TEMPLATE=$KB_API_URL_TEMPLATE
|
11
|
+
- KB_PARTNER_KEY=$KB_PARTNER_KEY
|
12
|
+
- KB_API_KEY=$KB_API_KEY
|
13
|
+
|
14
|
+
volumes:
|
15
|
+
bundle:
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'kb/fake'
|
data/lib/barkibu-kb.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require'byebug'
|
2
|
+
require 'kb/version'
|
3
|
+
require 'active_model'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext/array'
|
7
|
+
require 'faraday'
|
8
|
+
require 'faraday_middleware'
|
9
|
+
require 'faraday/http'
|
10
|
+
require 'dry/configurable'
|
11
|
+
|
12
|
+
module KB
|
13
|
+
extend Dry::Configurable
|
14
|
+
|
15
|
+
setting :cache do
|
16
|
+
setting :instance, default: ActiveSupport::Cache::NullStore.new
|
17
|
+
setting :expires_in, default: 0
|
18
|
+
end
|
19
|
+
|
20
|
+
setting :log_level, default: :info
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'kb/inflections'
|
24
|
+
|
25
|
+
require 'kb/cache'
|
26
|
+
require 'kb/client_resolver'
|
27
|
+
require 'kb/errors'
|
28
|
+
require 'kb/client'
|
29
|
+
|
30
|
+
require 'kb/concerns'
|
31
|
+
require 'kb/models'
|
32
|
+
|
33
|
+
require 'kb/validators'
|
data/lib/kb/cache.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module KB
|
2
|
+
class Cache
|
3
|
+
class << self
|
4
|
+
def delete(key)
|
5
|
+
instance.delete(key)
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(key, &block)
|
9
|
+
instance.fetch(key, expires_in: cache_expiration, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def instance
|
15
|
+
KB.config.cache.instance
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache_expiration
|
19
|
+
KB.config.cache.expires_in.to_f
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/kb/client.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module KB
|
2
|
+
class Client
|
3
|
+
attr_reader :api_key, :base_url
|
4
|
+
|
5
|
+
def initialize(base_url, api_key: ENV['KB_API_KEY'])
|
6
|
+
@api_key = api_key
|
7
|
+
@base_url = base_url
|
8
|
+
end
|
9
|
+
|
10
|
+
def request(sub_path, filters: nil, method: :get)
|
11
|
+
return connection.public_send(method, sub_path, filters).body if method != :get
|
12
|
+
|
13
|
+
cache_key = "#{@base_url}/#{sub_path}/#{(filters || {}).sort.to_h}"
|
14
|
+
KB::Cache.fetch(cache_key) do
|
15
|
+
connection.public_send(method, sub_path, filters).body
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def all(filters = {})
|
20
|
+
cache_key = "#{@base_url}/#{filters.sort.to_h}"
|
21
|
+
|
22
|
+
KB::Cache.fetch(cache_key) do
|
23
|
+
connection.get('', attributes_case_transform(filters)).body
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find(key, params = {})
|
28
|
+
raise Faraday::ResourceNotFound, {} if key.blank?
|
29
|
+
|
30
|
+
KB::Cache.fetch("#{@base_url}/#{key}") do
|
31
|
+
connection.get(key, attributes_case_transform(params)).body
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create(attributes)
|
36
|
+
connection.post('', attributes_to_json(attributes)).body
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(key, attributes)
|
40
|
+
KB::Cache.delete("#{@base_url}/#{key}")
|
41
|
+
connection.patch(key.to_s, attributes_to_json(attributes)).body
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy(key)
|
45
|
+
KB::Cache.delete("#{@base_url}/#{key}")
|
46
|
+
connection.delete(key.to_s).body
|
47
|
+
end
|
48
|
+
|
49
|
+
def upsert(attributes)
|
50
|
+
connection.put('', attributes_to_json(attributes)).body
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def headers
|
56
|
+
{
|
57
|
+
'Content-Type': 'application/json',
|
58
|
+
'x-api-key': api_key
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes_case_transform(attributes)
|
63
|
+
attributes.transform_keys do |key|
|
64
|
+
key.to_s.camelize(:lower)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def attributes_to_json(attributes)
|
69
|
+
attributes_case_transform(attributes).to_json
|
70
|
+
end
|
71
|
+
|
72
|
+
def connection
|
73
|
+
@connection ||= Faraday.new(url: base_url, headers: headers) do |conn|
|
74
|
+
conn.response :json
|
75
|
+
conn.response :raise_error
|
76
|
+
if KB.config.log_level == :debugger
|
77
|
+
conn.response :logger do |logger|
|
78
|
+
logger.filter(/(X-api-key:\s)("\w+")/, '\1[API_KEY_SCRUBBED]')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
conn.adapter :http
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module KB
|
2
|
+
class ClientResolver
|
3
|
+
class << self
|
4
|
+
def consultation
|
5
|
+
call :petfamily, :consultations, :v1
|
6
|
+
end
|
7
|
+
|
8
|
+
def admin
|
9
|
+
call :petfamily, :admin
|
10
|
+
end
|
11
|
+
|
12
|
+
def pet_parent
|
13
|
+
call :petfamily, :petparents
|
14
|
+
end
|
15
|
+
|
16
|
+
def pet
|
17
|
+
call :petfamily, :pets
|
18
|
+
end
|
19
|
+
|
20
|
+
def pet_contract
|
21
|
+
call :petfamily, :petcontracts
|
22
|
+
end
|
23
|
+
|
24
|
+
def breed
|
25
|
+
call :petfamily, :breeds
|
26
|
+
end
|
27
|
+
|
28
|
+
def plan
|
29
|
+
call :petfamily, :plans
|
30
|
+
end
|
31
|
+
|
32
|
+
def product
|
33
|
+
call :petfamily, :products
|
34
|
+
end
|
35
|
+
|
36
|
+
def hubspot
|
37
|
+
call :petfamily, :hubspot
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(*args, &block)
|
41
|
+
new(*args, &block).call
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :template, :bounded_context, :entity, :version
|
46
|
+
|
47
|
+
def initialize(bounded_context, entity, version = 'v1', template: ENV['KB_API_URL_TEMPLATE'])
|
48
|
+
@bounded_context = bounded_context
|
49
|
+
@entity = entity
|
50
|
+
@version = version
|
51
|
+
@template = template
|
52
|
+
end
|
53
|
+
|
54
|
+
def call
|
55
|
+
KB::Client.new base_url
|
56
|
+
end
|
57
|
+
|
58
|
+
def base_url
|
59
|
+
format(template, bounded_context: bounded_context, entity: entity, version: version).gsub('..', '.')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module KB
|
2
|
+
module Concerns
|
3
|
+
module AsKBWrapper
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_writer :kb_model
|
8
|
+
|
9
|
+
def save_underlying_kb_entity!
|
10
|
+
kb_model.save!
|
11
|
+
self.kb_key = kb_model.key if kb_model.key.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
def destroy_underlying_kb_entity
|
15
|
+
kb_model.destroy!
|
16
|
+
end
|
17
|
+
|
18
|
+
def reload(**options)
|
19
|
+
@kb_model = nil
|
20
|
+
super(**options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
|
25
|
+
class_methods do
|
26
|
+
def wrap_kb(model:, skip_callback: false)
|
27
|
+
before_save :save_underlying_kb_entity! unless skip_callback
|
28
|
+
before_destroy :destroy_underlying_kb_entity unless skip_callback
|
29
|
+
|
30
|
+
define_method(:kb_model) do
|
31
|
+
underlying_kb_entity = @kb_model
|
32
|
+
|
33
|
+
if underlying_kb_entity.blank?
|
34
|
+
underlying_kb_entity = begin
|
35
|
+
model.find kb_key
|
36
|
+
rescue KB::ResourceNotFound
|
37
|
+
model.new
|
38
|
+
end
|
39
|
+
|
40
|
+
@kb_model = underlying_kb_entity
|
41
|
+
end
|
42
|
+
|
43
|
+
underlying_kb_entity
|
44
|
+
end
|
45
|
+
|
46
|
+
singleton_class.instance_eval do
|
47
|
+
define_method(:kb_find_by) do |**attributes|
|
48
|
+
kb_model = model.all(attributes).first
|
49
|
+
return nil if kb_model.nil?
|
50
|
+
|
51
|
+
local_model = find_by(kb_key: kb_model.key)
|
52
|
+
return nil if local_model.nil?
|
53
|
+
|
54
|
+
local_model.kb_model = kb_model
|
55
|
+
local_model
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def kb_find_by!(**attributes)
|
61
|
+
kb_find_by(attributes).presence || raise(ActiveRecord::RecordNotFound)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/kb/concerns.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'kb/concerns/as_kb_wrapper'
|