f_http_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +121 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +132 -0
- data/LICENSE +21 -0
- data/README.md +126 -0
- data/Rakefile +12 -0
- data/examples/post_find.rb +31 -0
- data/lib/f_http_client/base.rb +114 -0
- data/lib/f_http_client/cache/http_response_analizer.rb +29 -0
- data/lib/f_http_client/cache/key.rb +14 -0
- data/lib/f_http_client/cache/null.rb +13 -0
- data/lib/f_http_client/cache/rails.rb +32 -0
- data/lib/f_http_client/configuration.rb +14 -0
- data/lib/f_http_client/log.rb +38 -0
- data/lib/f_http_client/logger/default.rb +40 -0
- data/lib/f_http_client/logger/null.rb +16 -0
- data/lib/f_http_client/logger/rails.rb +16 -0
- data/lib/f_http_client/parser/response.rb +16 -0
- data/lib/f_http_client/processor/exception.rb +49 -0
- data/lib/f_http_client/processor/response.rb +125 -0
- data/lib/f_http_client/rspec/support/helpers/fake_response.rb +15 -0
- data/lib/f_http_client/rspec/support/helpers.rb +3 -0
- data/lib/f_http_client/rspec/support/support.rb +3 -0
- data/lib/f_http_client/rspec/support.rb +3 -0
- data/lib/f_http_client/rspec.rb +3 -0
- data/lib/f_http_client/service.rb +22 -0
- data/lib/f_http_client/store.rb +37 -0
- data/lib/f_http_client/version.rb +5 -0
- data/lib/f_http_client.rb +34 -0
- data/sig/f_http_client.rbs +4 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fa009fca4cb5465b7a9c07e71037e15c5dffbbe97804e1b6a7ee2888cbfa771c
|
4
|
+
data.tar.gz: '058b8ef192570f144a44c4dac7e7f95aa401923f4176522944421b507b93e7e0'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a80d429fdc6fc7134ffeee8d6d627a87bad579dc4b29c38113e1a927e503cca3174de5d45829a0a39eb535c3c35b1193a2c3971bdad02acbfdc1cf04e305f1bc
|
7
|
+
data.tar.gz: e1f5e810e2fb1003fa8d503b7703699c75e2c1dc139062306b6eb1ade158cbdc1fe2273ea0cf76d772858a7cc803d61dfa2f3f4d29622d5103b5a7476f24123b
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
- rubocop-performance
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
TargetRubyVersion: 3.0
|
7
|
+
SuggestExtensions: false
|
8
|
+
NewCops: enable
|
9
|
+
CacheRootDirectory: tmp
|
10
|
+
Exclude:
|
11
|
+
- 'vendor/**/*'
|
12
|
+
- 'bin/**/*'
|
13
|
+
- '.git/**/*'
|
14
|
+
- 'examples/**/*'
|
15
|
+
|
16
|
+
##### LAYOUT #####
|
17
|
+
|
18
|
+
Layout/FirstArrayElementIndentation:
|
19
|
+
Enabled: true
|
20
|
+
EnforcedStyle: consistent
|
21
|
+
|
22
|
+
Layout/FirstHashElementIndentation:
|
23
|
+
Enabled: true
|
24
|
+
EnforcedStyle: consistent
|
25
|
+
|
26
|
+
Layout/LineLength:
|
27
|
+
Max: 120
|
28
|
+
AllowedPatterns: ['(\A|\s)#']
|
29
|
+
|
30
|
+
##### STYLE #####
|
31
|
+
|
32
|
+
Style/PreferredHashMethods:
|
33
|
+
Enabled: true
|
34
|
+
Safe: false
|
35
|
+
EnforcedStyle: verbose
|
36
|
+
|
37
|
+
Style/SymbolArray:
|
38
|
+
Enabled: true
|
39
|
+
EnforcedStyle: percent
|
40
|
+
MinSize: 3
|
41
|
+
|
42
|
+
Style/WordArray:
|
43
|
+
Enabled: true
|
44
|
+
EnforcedStyle: percent
|
45
|
+
MinSize: 3
|
46
|
+
|
47
|
+
Style/MultilineBlockChain:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/Lambda:
|
51
|
+
Enabled: true
|
52
|
+
EnforcedStyle: literal
|
53
|
+
|
54
|
+
Style/LambdaCall:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Style/Documentation:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Style/ClassAndModuleChildren:
|
61
|
+
Enabled: false
|
62
|
+
|
63
|
+
##### LINT #####
|
64
|
+
|
65
|
+
Lint/MissingSuper:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
##### NAMING #####
|
69
|
+
|
70
|
+
Naming/InclusiveLanguage:
|
71
|
+
Enabled: false
|
72
|
+
|
73
|
+
Naming/PredicateName:
|
74
|
+
ForbiddenPrefixes:
|
75
|
+
- is_
|
76
|
+
- have_
|
77
|
+
# allows `has_` predicate
|
78
|
+
|
79
|
+
###### METRICS #####
|
80
|
+
|
81
|
+
Metrics/AbcSize:
|
82
|
+
Enabled: true
|
83
|
+
Max: 22
|
84
|
+
|
85
|
+
Metrics/BlockLength:
|
86
|
+
Enabled: true
|
87
|
+
CountComments: false
|
88
|
+
Exclude:
|
89
|
+
- '**/*.gemspec'
|
90
|
+
- 'spec/**/*'
|
91
|
+
|
92
|
+
Metrics/ClassLength:
|
93
|
+
Max: 200
|
94
|
+
|
95
|
+
Metrics/MethodLength:
|
96
|
+
Enabled: true
|
97
|
+
CountAsOne: ['array', 'heredoc']
|
98
|
+
Max: 20
|
99
|
+
|
100
|
+
##### RSPEC #####
|
101
|
+
|
102
|
+
RSpec/ContextWording:
|
103
|
+
Prefixes:
|
104
|
+
- and
|
105
|
+
- but
|
106
|
+
- when
|
107
|
+
- with
|
108
|
+
- without
|
109
|
+
|
110
|
+
RSpec/ExampleLength:
|
111
|
+
Max: 20
|
112
|
+
|
113
|
+
RSpec/FilePath:
|
114
|
+
CustomTransform:
|
115
|
+
FHTTPClient: f_http_client
|
116
|
+
|
117
|
+
RSpec/MultipleMemoizedHelpers:
|
118
|
+
Enabled: false
|
119
|
+
|
120
|
+
RSpec/NestedGroups:
|
121
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
## [Unreleased]
|
2
|
+
|
3
|
+
## [0.1.0] - 2023-02-13
|
4
|
+
|
5
|
+
- Initial release
|
6
|
+
- Add Caching strategies;
|
7
|
+
- Add Logging strategies;
|
8
|
+
- Add Custom parse for JSON responses;
|
9
|
+
- Add Response and Exception processors;
|
10
|
+
- Add Base client class;
|
11
|
+
- Add Basic configuration;
|
12
|
+
- Add RSpec helpers to simulate responses
|
data/Gemfile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in f_http_client.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem 'f_service', github: 'Fretadao/f_service', branch: 'master'
|
10
|
+
gem 'rubocop'
|
11
|
+
gem 'rubocop-performance'
|
12
|
+
gem 'rubocop-rspec'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'rspec', '~> 3.0'
|
17
|
+
gem 'simplecov'
|
18
|
+
gem 'webmock'
|
19
|
+
end
|
20
|
+
|
21
|
+
group :development, :test do
|
22
|
+
gem 'pry'
|
23
|
+
gem 'pry-nav'
|
24
|
+
gem 'rake', '~> 13.0'
|
25
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/Fretadao/f_service.git
|
3
|
+
revision: 22d3e1c8bd4aa83b14f34b1af19aa4cd22b8ad8b
|
4
|
+
branch: master
|
5
|
+
specs:
|
6
|
+
f_service (0.2.0)
|
7
|
+
|
8
|
+
PATH
|
9
|
+
remote: .
|
10
|
+
specs:
|
11
|
+
f_http_client (0.1.0)
|
12
|
+
activesupport
|
13
|
+
addressable
|
14
|
+
dry-configurable
|
15
|
+
dry-initializer
|
16
|
+
httparty
|
17
|
+
|
18
|
+
GEM
|
19
|
+
remote: https://rubygems.org/
|
20
|
+
specs:
|
21
|
+
activesupport (7.0.4.3)
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
|
+
i18n (>= 1.6, < 2)
|
24
|
+
minitest (>= 5.1)
|
25
|
+
tzinfo (~> 2.0)
|
26
|
+
addressable (2.8.1)
|
27
|
+
public_suffix (>= 2.0.2, < 6.0)
|
28
|
+
ast (2.4.2)
|
29
|
+
coderay (1.1.3)
|
30
|
+
concurrent-ruby (1.2.2)
|
31
|
+
crack (0.4.5)
|
32
|
+
rexml
|
33
|
+
diff-lcs (1.5.0)
|
34
|
+
docile (1.4.0)
|
35
|
+
dry-configurable (1.0.1)
|
36
|
+
dry-core (~> 1.0, < 2)
|
37
|
+
zeitwerk (~> 2.6)
|
38
|
+
dry-core (1.0.0)
|
39
|
+
concurrent-ruby (~> 1.0)
|
40
|
+
zeitwerk (~> 2.6)
|
41
|
+
dry-initializer (3.1.1)
|
42
|
+
hashdiff (1.0.1)
|
43
|
+
httparty (0.21.0)
|
44
|
+
mini_mime (>= 1.0.0)
|
45
|
+
multi_xml (>= 0.5.2)
|
46
|
+
i18n (1.12.0)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
json (2.6.3)
|
49
|
+
method_source (1.0.0)
|
50
|
+
mini_mime (1.1.2)
|
51
|
+
minitest (5.18.0)
|
52
|
+
multi_xml (0.6.0)
|
53
|
+
parallel (1.22.1)
|
54
|
+
parser (3.2.1.0)
|
55
|
+
ast (~> 2.4.1)
|
56
|
+
pry (0.14.2)
|
57
|
+
coderay (~> 1.1)
|
58
|
+
method_source (~> 1.0)
|
59
|
+
pry-nav (1.0.0)
|
60
|
+
pry (>= 0.9.10, < 0.15)
|
61
|
+
public_suffix (5.0.1)
|
62
|
+
rainbow (3.1.1)
|
63
|
+
rake (13.0.6)
|
64
|
+
regexp_parser (2.7.0)
|
65
|
+
rexml (3.2.5)
|
66
|
+
rspec (3.12.0)
|
67
|
+
rspec-core (~> 3.12.0)
|
68
|
+
rspec-expectations (~> 3.12.0)
|
69
|
+
rspec-mocks (~> 3.12.0)
|
70
|
+
rspec-core (3.12.1)
|
71
|
+
rspec-support (~> 3.12.0)
|
72
|
+
rspec-expectations (3.12.2)
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
+
rspec-support (~> 3.12.0)
|
75
|
+
rspec-mocks (3.12.3)
|
76
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
77
|
+
rspec-support (~> 3.12.0)
|
78
|
+
rspec-support (3.12.0)
|
79
|
+
rubocop (1.45.1)
|
80
|
+
json (~> 2.3)
|
81
|
+
parallel (~> 1.10)
|
82
|
+
parser (>= 3.2.0.0)
|
83
|
+
rainbow (>= 2.2.2, < 4.0)
|
84
|
+
regexp_parser (>= 1.8, < 3.0)
|
85
|
+
rexml (>= 3.2.5, < 4.0)
|
86
|
+
rubocop-ast (>= 1.24.1, < 2.0)
|
87
|
+
ruby-progressbar (~> 1.7)
|
88
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
89
|
+
rubocop-ast (1.26.0)
|
90
|
+
parser (>= 3.2.1.0)
|
91
|
+
rubocop-capybara (2.17.1)
|
92
|
+
rubocop (~> 1.41)
|
93
|
+
rubocop-performance (1.16.0)
|
94
|
+
rubocop (>= 1.7.0, < 2.0)
|
95
|
+
rubocop-ast (>= 0.4.0)
|
96
|
+
rubocop-rspec (2.18.1)
|
97
|
+
rubocop (~> 1.33)
|
98
|
+
rubocop-capybara (~> 2.17)
|
99
|
+
ruby-progressbar (1.11.0)
|
100
|
+
simplecov (0.22.0)
|
101
|
+
docile (~> 1.1)
|
102
|
+
simplecov-html (~> 0.11)
|
103
|
+
simplecov_json_formatter (~> 0.1)
|
104
|
+
simplecov-html (0.12.3)
|
105
|
+
simplecov_json_formatter (0.1.4)
|
106
|
+
tzinfo (2.0.6)
|
107
|
+
concurrent-ruby (~> 1.0)
|
108
|
+
unicode-display_width (2.4.2)
|
109
|
+
webmock (3.18.1)
|
110
|
+
addressable (>= 2.8.0)
|
111
|
+
crack (>= 0.3.2)
|
112
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
113
|
+
zeitwerk (2.6.7)
|
114
|
+
|
115
|
+
PLATFORMS
|
116
|
+
x86_64-linux
|
117
|
+
|
118
|
+
DEPENDENCIES
|
119
|
+
f_http_client!
|
120
|
+
f_service!
|
121
|
+
pry
|
122
|
+
pry-nav
|
123
|
+
rake (~> 13.0)
|
124
|
+
rspec (~> 3.0)
|
125
|
+
rubocop
|
126
|
+
rubocop-performance
|
127
|
+
rubocop-rspec
|
128
|
+
simplecov
|
129
|
+
webmock
|
130
|
+
|
131
|
+
BUNDLED WITH
|
132
|
+
2.4.6
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 Fretadão
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# FHTTPClient
|
2
|
+
|
3
|
+
Provides a basic skeleton for creating an HTTP client using the FService architecture.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add to your `.gemspec` client file `spec.add_runtime_dependency 'f_http_client'` and run `bundle install`.
|
8
|
+
|
9
|
+
## Configure
|
10
|
+
|
11
|
+
The gem allow the following configuration
|
12
|
+
|
13
|
+
- base_uri: a URI to be used for all services for your client;
|
14
|
+
- log_strategy: s symbol representing which logger the gem will use;
|
15
|
+
- null (default): means that the client will not log anything;
|
16
|
+
- rails: means that Rails logger will be used;
|
17
|
+
- any other value the gem will use a default logger which loggs at STDOUT.
|
18
|
+
- cache
|
19
|
+
- strategy: Defines which cache strategy will be used;
|
20
|
+
- null (default): the client does not log anything;
|
21
|
+
- rails: the Rails.cache will be used to perform caching;
|
22
|
+
- expires_in: Deines in seconds how much time the cache will be kept (default 0).
|
23
|
+
|
24
|
+
```rb
|
25
|
+
module BlogClient
|
26
|
+
class Configuration < FHTTPClient::Configuration
|
27
|
+
setting :paginate do
|
28
|
+
setting :enabled, default: true
|
29
|
+
setting :per_page, :20
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
BlogClient::Configuration.configure do |config|
|
35
|
+
config.base_uri = 'https://jsonplaceholder.typicode.com'
|
36
|
+
confg.log_strategy = :rails
|
37
|
+
|
38
|
+
config.cache.strategy = :rails
|
39
|
+
config.cache.expires_in = 25.minutes
|
40
|
+
config.paginate.per_page = 50
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class BlogClient::Base < FHTTPClient::Base
|
45
|
+
def self.config
|
46
|
+
BlogClient::Configuration.config
|
47
|
+
end
|
48
|
+
|
49
|
+
cache_expires_in 10.minutes
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
## Usage
|
54
|
+
|
55
|
+
Could create a class:
|
56
|
+
|
57
|
+
```rb
|
58
|
+
# frozen_string_literal: true
|
59
|
+
|
60
|
+
module BlogClient
|
61
|
+
module Post
|
62
|
+
class Find < BlogClient::Base
|
63
|
+
private
|
64
|
+
|
65
|
+
def make_request
|
66
|
+
self.class.get(formatted_path, headers: headers)
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_template
|
70
|
+
'/posts/%<id>s'
|
71
|
+
end
|
72
|
+
|
73
|
+
def headers
|
74
|
+
@headers.merge(content_type: 'application/json')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# BlogClient::Post::Find.(path_params: { id: 1 })
|
81
|
+
# .and_then { |response| response.parsed_response }
|
82
|
+
#
|
83
|
+
# => {
|
84
|
+
# userId: 1,
|
85
|
+
# id: 1,
|
86
|
+
# title: "How to use a FHTTPCLient Gem",
|
87
|
+
# body: "A great text here."
|
88
|
+
# }
|
89
|
+
```
|
90
|
+
|
91
|
+
Result examples:
|
92
|
+
|
93
|
+
```rb
|
94
|
+
Person::Create.(name: 'Joe Vicenzo', birthdate: '2000-01-01')
|
95
|
+
.and_then { |user| return redirect_to users_path(user.id) }
|
96
|
+
.on_failure(:unprocessable_entity) { |errors| return render_action :new, locals: { errors: errors } }
|
97
|
+
.on_failure(:client_error) { |errors| render_action :new, warning: errors }
|
98
|
+
.on_failure(:server_error) { |error| render_action :new, warning: ['Try again latter.'] }
|
99
|
+
.on_failure(:server_error) { |error| render_action :new, warning: ['Server is busy. Try again latter.'] }
|
100
|
+
.on_failure { |_error, type| render_action :new, warning: ["Unexpected error. Contact admin and talk about #{type} error."] }
|
101
|
+
```
|
102
|
+
|
103
|
+
This gem uses the gem [HTTParty](https://github.com/jnunemaker/httparty) as base to perform requests.
|
104
|
+
Then we can use any [example](https://github.com/jnunemaker/httparty/tree/master/examples) to implements the method make_request, for GET, POST, PUT, etc.
|
105
|
+
The class *FHTTPClient::Base* provides the following options to help building the request:
|
106
|
+
- *headers*: can be used to provide custom headers;
|
107
|
+
- *query*: can be used to provide querystring params;
|
108
|
+
- *body*: can be used to provide a body when request requires this;
|
109
|
+
- *options*: can be used provide any other option for HTTParty;
|
110
|
+
- *path_params*, can be used to fills params which is in the request path.
|
111
|
+
|
112
|
+
## Development
|
113
|
+
|
114
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
115
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
116
|
+
|
117
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
118
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
119
|
+
|
120
|
+
## Contributing
|
121
|
+
|
122
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Fretadao/f_http_client.
|
123
|
+
|
124
|
+
## License
|
125
|
+
|
126
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Post
|
4
|
+
class Find < FHTTPClient::Base
|
5
|
+
base_uri 'https://jsonplaceholder.typicode.com'
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def make_request
|
10
|
+
self.class.get(formatted_path, headers: headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
def path_template
|
14
|
+
'/posts/%<id>s'
|
15
|
+
end
|
16
|
+
|
17
|
+
def headers
|
18
|
+
@headers.merge(content_type: 'application/json')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Post::Find.(path_params: { id: 1 })
|
24
|
+
# .and_then { |response| response.parsed_response }
|
25
|
+
#
|
26
|
+
# => {
|
27
|
+
# userId: 1,
|
28
|
+
# id: 1,
|
29
|
+
# title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
|
30
|
+
# body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
|
31
|
+
# }
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
# Allows to have an http client to build a service
|
5
|
+
# @abstract
|
6
|
+
class Base < FHTTPClient::Service
|
7
|
+
include HTTParty
|
8
|
+
|
9
|
+
DEFAULT_SKIP_CACHE_IF = ->(response) { FHTTPClient::Cache::HTTPResponseAnalyzer.not_cacheable?(response) }
|
10
|
+
|
11
|
+
option :headers, default: -> { {} }
|
12
|
+
option :query, default: -> { {} }
|
13
|
+
option :body, default: -> { {} }
|
14
|
+
option :options, default: -> { {} }
|
15
|
+
option :path_params, default: -> { {} }
|
16
|
+
|
17
|
+
parser FHTTPClient::Parser::Response
|
18
|
+
|
19
|
+
def run
|
20
|
+
configure_base_uri.and_then do
|
21
|
+
response = make_cached_request.value!
|
22
|
+
|
23
|
+
FHTTPClient::Processor::Response.(response: response, log_strategy: log_strategy)
|
24
|
+
end
|
25
|
+
rescue StandardError => e
|
26
|
+
FHTTPClient::Processor::Exception.(error: e, log_strategy: log_strategy)
|
27
|
+
.on_failure(:uncaught_error) { raise e }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.config
|
31
|
+
raise NotImplementedError, 'Clients must implement .config'
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.cache_strategy(strategy = nil)
|
35
|
+
default_options[:cache_strategy] = config.cache.strategy if default_options[:cache_strategy].nil?
|
36
|
+
return default_options[:cache_strategy] unless strategy
|
37
|
+
|
38
|
+
default_options[:cache_strategy] = strategy
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.cache_expires_in(expires_in = nil)
|
42
|
+
default_options[:cache_expires_in] = config.cache.expires_in if default_options[:cache_expires_in].nil?
|
43
|
+
|
44
|
+
return default_options[:cache_expires_in] unless expires_in
|
45
|
+
|
46
|
+
default_options[:cache_expires_in] = expires_in
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def configure_base_uri
|
52
|
+
return Success(:uri_already_configured) if self.class.base_uri.present?
|
53
|
+
|
54
|
+
return Failure(:no_base_uri_configured) if config.base_uri.blank?
|
55
|
+
|
56
|
+
self.class.base_uri(config.base_uri)
|
57
|
+
|
58
|
+
Success(:base_uri_configured)
|
59
|
+
end
|
60
|
+
|
61
|
+
def make_cached_request
|
62
|
+
FHTTPClient::Store.(
|
63
|
+
key: cache_key,
|
64
|
+
strategy: cache_strategy,
|
65
|
+
block: -> { make_request },
|
66
|
+
expires_in: cache_expires_in,
|
67
|
+
skip_if: skip_cache_if
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def make_request
|
72
|
+
raise NotImplementedError, 'Clients must implement #make_request'
|
73
|
+
end
|
74
|
+
|
75
|
+
def path_template
|
76
|
+
raise NotImplementedError, 'Clients must implement #path_template'
|
77
|
+
end
|
78
|
+
|
79
|
+
def formatted_path
|
80
|
+
@formatted_path ||= format(path_template, path_params)
|
81
|
+
end
|
82
|
+
|
83
|
+
def cache_key
|
84
|
+
FHTTPClient::Cache::Key.generate(
|
85
|
+
self.class,
|
86
|
+
path: formatted_path,
|
87
|
+
headers: headers,
|
88
|
+
query: query,
|
89
|
+
body: body,
|
90
|
+
options: options
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def config
|
95
|
+
self.class.config
|
96
|
+
end
|
97
|
+
|
98
|
+
def log_strategy
|
99
|
+
config.log_strategy
|
100
|
+
end
|
101
|
+
|
102
|
+
def cache_strategy
|
103
|
+
self.class.default_options[:cache_strategy] || config.cache.strategy
|
104
|
+
end
|
105
|
+
|
106
|
+
def cache_expires_in
|
107
|
+
self.class.default_options[:cache_expires_in] || config.cache.expires_in
|
108
|
+
end
|
109
|
+
|
110
|
+
def skip_cache_if
|
111
|
+
DEFAULT_SKIP_CACHE_IF
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Cache
|
5
|
+
module HTTPResponseAnalyzer
|
6
|
+
attr_reader :response
|
7
|
+
|
8
|
+
NOT_CACHEABLE_RESPONSES = %i[
|
9
|
+
server_error?
|
10
|
+
gateway_timeout?
|
11
|
+
request_timeout?
|
12
|
+
unauthorized?
|
13
|
+
too_many_requests?
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def not_cacheable_responses
|
18
|
+
NOT_CACHEABLE_RESPONSES
|
19
|
+
end
|
20
|
+
|
21
|
+
def not_cacheable?(response)
|
22
|
+
not_cacheable_responses.any? do |not_cacheable_response|
|
23
|
+
response.public_send(not_cacheable_response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Cache
|
5
|
+
class Key
|
6
|
+
def self.generate(*args)
|
7
|
+
params = args.extract_options!
|
8
|
+
klass = args.first.to_s
|
9
|
+
|
10
|
+
[klass.underscore, params.compact_blank.to_query].filter_map(&:presence).join('?')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Cache
|
5
|
+
RailsNotDefined = Class.new(StandardError)
|
6
|
+
|
7
|
+
class Rails
|
8
|
+
class << self
|
9
|
+
def fetch(name, options = {})
|
10
|
+
raise RailsNotDefined unless defined?(::Rails)
|
11
|
+
|
12
|
+
cache_entry = cache.read(name)
|
13
|
+
|
14
|
+
return cache_entry if cache_entry.present?
|
15
|
+
return unless block_given?
|
16
|
+
|
17
|
+
result = yield
|
18
|
+
|
19
|
+
cache.write(name, result, options) unless options[:skip_if]&.(result)
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def cache
|
27
|
+
::Rails.cache
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
class Configuration
|
5
|
+
extend Dry::Configurable
|
6
|
+
|
7
|
+
setting :base_uri
|
8
|
+
setting :log_strategy, default: :null
|
9
|
+
setting :cache do
|
10
|
+
setting :strategy, default: :null
|
11
|
+
setting :expires_in, default: 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
# Allow to log a message to system log
|
5
|
+
#
|
6
|
+
# Attributes:
|
7
|
+
# - message: object containint the message to be logged;
|
8
|
+
# - level (optional): level symbol to log the message (debug, info, warn error, fatal or unknown);
|
9
|
+
# - tags (optional): list of tags to be added to log line.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# FHTTPClient::Log.(message: { name: 'Bruno' }.to_json)
|
13
|
+
# FHTTPClient::Log.(message: { name: 'Bruno' }.to_json, stragegy: :rails)
|
14
|
+
# FHTTPClient::Log.(message: { name: 'Bruno' }.to_json, tags: ['Response'])
|
15
|
+
# FHTTPClient::Log.(message: { response: { name: 'Bruno' } }.to_json, level: :warn)
|
16
|
+
class Log < FHTTPClient::Service
|
17
|
+
LOGGERS = {
|
18
|
+
rails: FHTTPClient::Logger::Rails,
|
19
|
+
default: FHTTPClient::Logger::Default
|
20
|
+
}.freeze
|
21
|
+
private_constant :LOGGERS
|
22
|
+
|
23
|
+
option :message
|
24
|
+
option :strategy, default: -> { :null }
|
25
|
+
option :level, default: -> { :info }
|
26
|
+
option :tags, default: -> { [] }
|
27
|
+
|
28
|
+
def run
|
29
|
+
logger.tagged(*Array(tags)).public_send(level, message)
|
30
|
+
|
31
|
+
Success(:logged)
|
32
|
+
end
|
33
|
+
|
34
|
+
def logger
|
35
|
+
@logger ||= LOGGERS.fetch(strategy, FHTTPClient::Logger::Null).new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Logger
|
5
|
+
# A Basic logger to use when no logger is provided
|
6
|
+
class Default
|
7
|
+
def initialize(tags: [])
|
8
|
+
@logger = ::Logger.new($stdout)
|
9
|
+
@current_tags = tags
|
10
|
+
end
|
11
|
+
|
12
|
+
def tagged(*tags)
|
13
|
+
tagged = self.class.new(tags: current_tags + tags)
|
14
|
+
block_given? ? yield(tagged) : tagged
|
15
|
+
end
|
16
|
+
|
17
|
+
def debug(message) = add(::Logger::DEBUG, message)
|
18
|
+
def info(message) = add(::Logger::INFO, message)
|
19
|
+
def warn(message) = add(::Logger::WARN, message)
|
20
|
+
def error(message) = add(::Logger::ERROR, message)
|
21
|
+
def fatal(message) = add(::Logger::FATAL, message)
|
22
|
+
def unknown(message) = add(::Logger::UNKNOWN, message)
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :logger, :current_tags
|
27
|
+
|
28
|
+
def add(severity, message)
|
29
|
+
formatted_tags = format_tags
|
30
|
+
full_message = formatted_tags.empty? ? message : [format_tags, message].join(' - ')
|
31
|
+
|
32
|
+
logger.add(severity, full_message)
|
33
|
+
end
|
34
|
+
|
35
|
+
def format_tags
|
36
|
+
current_tags.map { |tag| "[#{tag}]" }.join(' ')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Logger
|
5
|
+
# Logs nothing
|
6
|
+
class Null
|
7
|
+
def tagged(...) = block_given? ? yield(self) : self
|
8
|
+
def debug(...) = nil
|
9
|
+
def info(...) = nil
|
10
|
+
def warn(...) = nil
|
11
|
+
def error(...) = nil
|
12
|
+
def fatal(...) = nil
|
13
|
+
def unknown(...) = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Logger
|
5
|
+
# Logging with Rails logger
|
6
|
+
class Rails
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
delegate %i[tagged debug info warn error fatal unknown] => :@logger
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@logger = ::Rails.logger
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Parser
|
5
|
+
# Parse a json response letting this as symbol hash
|
6
|
+
# Following those examples: https://github.com/jnunemaker/httparty/blob/master/examples/custom_parsers.rb
|
7
|
+
# And looking default formats: https://github.com/jnunemaker/httparty/blob/fb7c40303b7e6429196ef748754505768520407c/lib/httparty/parser.rb#L42
|
8
|
+
class Response < HTTParty::Parser
|
9
|
+
protected
|
10
|
+
|
11
|
+
def json
|
12
|
+
JSON.parse(body, quirks_mode: true, allow_nan: true, symbolize_names: true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Processor
|
5
|
+
# This Service proccess a HTTP exception generating failure result.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# def process
|
10
|
+
# error = Errno::ECONNREFUSED.new('Failed to open TCP connection to :80')
|
11
|
+
# FHTTPClient::Processor::ResponseProcessor.(error: error)
|
12
|
+
# .on_failure(:connection_refused) { return 'The server has been refused the connection.' }
|
13
|
+
# .on_failure { |error_message| return "Generic #{error_message}" }
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# proccess
|
17
|
+
# # => 'The server has been refused the connection.'
|
18
|
+
class Exception < FHTTPClient::Service
|
19
|
+
option :error
|
20
|
+
option :log_strategy, default: -> { :null }
|
21
|
+
|
22
|
+
def run
|
23
|
+
log_data.and_then { Failure(error_name, :exception, data: error) }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def error_name
|
29
|
+
case error.class.to_s
|
30
|
+
when 'Errno::ECONNREFUSED'
|
31
|
+
:connection_refused
|
32
|
+
when /timeout/i
|
33
|
+
:timeout
|
34
|
+
else
|
35
|
+
:uncaught_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_data
|
40
|
+
FHTTPClient::Log.(
|
41
|
+
message: { error: error.class.to_s, message: error.message, backtrace: error.backtrace.join(', ') }.to_json,
|
42
|
+
tags: 'EXTERNAL REQUEST',
|
43
|
+
level: :error,
|
44
|
+
strategy: log_strategy
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
module Processor
|
5
|
+
# This Service proccess a HTTP response, generating a success or failure result.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# def process
|
10
|
+
# response = OpenStruct.new(success?: false, parsed_response: {}, headers: {}, message: 'Conflict')
|
11
|
+
# processor = FHTTPClient::Processor::Response.new(response: response)
|
12
|
+
# processor.()
|
13
|
+
# .on_success { |value| "Success! #{value.inspect}"}
|
14
|
+
# .on_failure(:conflict) { |value| return "A conflict happened! #{value.inspect}"}
|
15
|
+
# .on_failure(:client_error) { |value| return "An unexpected client error happened #{value.inspect}"}
|
16
|
+
# .on_failure { |value| return "Generic #{value}" }
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# proccess
|
20
|
+
# # => "A conflict happened! {}"
|
21
|
+
class Response < FHTTPClient::Service
|
22
|
+
extend Forwardable
|
23
|
+
|
24
|
+
option :response
|
25
|
+
option :log_strategy, default: -> { :null }
|
26
|
+
|
27
|
+
STATUS_FAMILIES = {
|
28
|
+
200..299 => :successful,
|
29
|
+
400..499 => :client_error,
|
30
|
+
500..599 => :server_error,
|
31
|
+
300..399 => :redirection,
|
32
|
+
100..199 => :informational
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
private_constant :STATUS_FAMILIES
|
36
|
+
|
37
|
+
def run
|
38
|
+
log_data.and_then { success? ? success_response : failure_response }
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def_delegators :@response, :headers, :success?, :parsed_response, :code
|
44
|
+
|
45
|
+
def success_response
|
46
|
+
Success(response_type, response_family, data: response)
|
47
|
+
end
|
48
|
+
|
49
|
+
def failure_response
|
50
|
+
Failure(response_type, response_family, data: response)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Private:
|
54
|
+
# Transform HTTParty response message in to a symbol
|
55
|
+
# Ex: When the request returns a 400 (Bad Request)
|
56
|
+
#
|
57
|
+
# # => :bad_request
|
58
|
+
def response_type
|
59
|
+
message.empty? ? :unknown_type : message.downcase.tr(' ', '_').to_sym
|
60
|
+
end
|
61
|
+
|
62
|
+
# Private:
|
63
|
+
# Transform HTTParty response code in to a symbol
|
64
|
+
# Ex: When the request returns a 400 (Bad Request)
|
65
|
+
#
|
66
|
+
# # => :client_error
|
67
|
+
def response_family
|
68
|
+
STATUS_FAMILIES
|
69
|
+
.find(-> { [code, :unknown_family] }) { |codes, _family| codes.cover?(code.to_i) }
|
70
|
+
.last
|
71
|
+
end
|
72
|
+
|
73
|
+
# Private
|
74
|
+
# Generates a HTTParty response message from a Net::HTTPRespoonse Class
|
75
|
+
# Examples:
|
76
|
+
#
|
77
|
+
# response_type(Net::HTTPOK)
|
78
|
+
# # => "OK"
|
79
|
+
#
|
80
|
+
# response_type(Net::HTTPUnprocessableEntity)
|
81
|
+
# # => "Unprocessable Entity"
|
82
|
+
def message
|
83
|
+
@message ||= response_class
|
84
|
+
.to_s
|
85
|
+
.delete_prefix('Net::HTTP')
|
86
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1 \2')
|
87
|
+
.gsub(/([a-z])([A-Z])/, '\1 \2')
|
88
|
+
end
|
89
|
+
|
90
|
+
# Private
|
91
|
+
# Get an HTTP status error name for a status code
|
92
|
+
#
|
93
|
+
# Ex: 400
|
94
|
+
# # => "Net:HTTPBadRequest"
|
95
|
+
def response_class
|
96
|
+
Net::HTTPResponse::CODE_TO_OBJ[code.to_s].to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def log_data
|
100
|
+
FHTTPClient::Log.(
|
101
|
+
message: { request: request_log_data, response: response_log_data }.to_json,
|
102
|
+
strategy: log_strategy,
|
103
|
+
tags: 'EXTERNAL REQUEST'
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def request_log_data
|
108
|
+
request = response.request
|
109
|
+
request_options = request.options
|
110
|
+
|
111
|
+
{
|
112
|
+
headers: request_options[:headers],
|
113
|
+
method: request.http_method.name.split('::').last.upcase,
|
114
|
+
path: request.uri.path,
|
115
|
+
querystring: Addressable::URI.parse(request.uri.query)&.query_values,
|
116
|
+
body: request_options[:body]
|
117
|
+
}.compact_blank
|
118
|
+
end
|
119
|
+
|
120
|
+
def response_log_data
|
121
|
+
{ code: code, human_code: message, headers: headers, body: parsed_response }.compact_blank
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClientFakeResponse
|
4
|
+
def build_httparty_response(code: 200, parsed_response: {})
|
5
|
+
request_object = HTTParty::Request.new Net::HTTP::Get, '/'
|
6
|
+
response_object = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new('1.1', code, '')
|
7
|
+
allow(response_object).to receive(:body)
|
8
|
+
|
9
|
+
HTTParty::Response.new(request_object, response_object, -> { parsed_response })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.include FHTTPClientFakeResponse
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
# Allow defining keyword args for a class
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class User::Create < FHTTPClient::Service
|
8
|
+
# option :name
|
9
|
+
# option :age
|
10
|
+
# option :email, default: -> { 'guest@user.com' }
|
11
|
+
#
|
12
|
+
# def run
|
13
|
+
# Success(:created, data: "Hello #{name}! Your email is: #{email}")
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# User.(name: 'Matheus', age: 22)
|
18
|
+
# => #<FService::Result::Success:0x0000557fae615ea8 @handled=false, @matching_types=[], @types=[:created], @value="Hello Bruno! Your email is: guest@user.com">
|
19
|
+
class Service < FService::Base
|
20
|
+
extend Dry::Initializer
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FHTTPClient
|
4
|
+
# Allow to log a message to system log
|
5
|
+
#
|
6
|
+
# Attributes:
|
7
|
+
# - strategy: symbol representing cache stragegy to be used (null or rails);
|
8
|
+
# - block: the lambda to have its result cached;
|
9
|
+
# - key: the cache key to be used to store the result;
|
10
|
+
# - expires_in (optional): seconds to keep the result in cache;
|
11
|
+
# - skip_if (optional): a block to run over the block result and decide if result caching must be persisted or skiped.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# FHTTPClient::Cache.(strategy: :rails, key: 'users/list?name=bruno', block: -> { make_request })
|
15
|
+
# FHTTPClient::Cache.(strategy: :rails, key: 'users/list?name=bruno', block: -> { make_request }, expires_in: 15.minutes)
|
16
|
+
# FHTTPClient::Cache.(strategy: :rails, key: 'users/list?name=bruno', block: -> { make_request }, skip_if: ->(response) { response.status != 200 })
|
17
|
+
class Store < FHTTPClient::Service
|
18
|
+
option :strategy
|
19
|
+
option :key
|
20
|
+
option :block
|
21
|
+
option :expires_in, default: -> {}
|
22
|
+
option :skip_if, default: -> {}
|
23
|
+
|
24
|
+
def run
|
25
|
+
Success(
|
26
|
+
:done,
|
27
|
+
data: cache.fetch(key, { expires_in: expires_in, skip_if: skip_if }.compact_blank, &block)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def cache
|
34
|
+
@cache ||= strategy == :rails ? FHTTPClient::Cache::Rails : FHTTPClient::Cache::Null
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'f_http_client/version'
|
4
|
+
require 'active_support/core_ext/array'
|
5
|
+
require 'active_support/core_ext/enumerable'
|
6
|
+
require 'active_support/core_ext/string'
|
7
|
+
require 'addressable'
|
8
|
+
require 'dry-configurable'
|
9
|
+
require 'dry-initializer'
|
10
|
+
require 'forwardable'
|
11
|
+
require 'httparty'
|
12
|
+
require 'f_service'
|
13
|
+
|
14
|
+
require 'f_http_client/configuration'
|
15
|
+
require 'f_http_client/service'
|
16
|
+
require 'f_http_client/store'
|
17
|
+
require 'f_http_client/cache/http_response_analizer'
|
18
|
+
require 'f_http_client/cache/key'
|
19
|
+
require 'f_http_client/cache/null'
|
20
|
+
require 'f_http_client/cache/rails'
|
21
|
+
|
22
|
+
require 'f_http_client/logger/default'
|
23
|
+
require 'f_http_client/logger/null'
|
24
|
+
require 'f_http_client/logger/rails'
|
25
|
+
require 'f_http_client/log'
|
26
|
+
|
27
|
+
require 'f_http_client/parser/response'
|
28
|
+
require 'f_http_client/processor/exception'
|
29
|
+
require 'f_http_client/processor/response'
|
30
|
+
|
31
|
+
require 'f_http_client/base'
|
32
|
+
|
33
|
+
module FHTTPClient
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: f_http_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fretadao Tech Team
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: addressable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-configurable
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dry-initializer
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: httparty
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- tech@fretadao.com.br
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".rspec"
|
91
|
+
- ".rubocop.yml"
|
92
|
+
- CHANGELOG.md
|
93
|
+
- Gemfile
|
94
|
+
- Gemfile.lock
|
95
|
+
- LICENSE
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- examples/post_find.rb
|
99
|
+
- lib/f_http_client.rb
|
100
|
+
- lib/f_http_client/base.rb
|
101
|
+
- lib/f_http_client/cache/http_response_analizer.rb
|
102
|
+
- lib/f_http_client/cache/key.rb
|
103
|
+
- lib/f_http_client/cache/null.rb
|
104
|
+
- lib/f_http_client/cache/rails.rb
|
105
|
+
- lib/f_http_client/configuration.rb
|
106
|
+
- lib/f_http_client/log.rb
|
107
|
+
- lib/f_http_client/logger/default.rb
|
108
|
+
- lib/f_http_client/logger/null.rb
|
109
|
+
- lib/f_http_client/logger/rails.rb
|
110
|
+
- lib/f_http_client/parser/response.rb
|
111
|
+
- lib/f_http_client/processor/exception.rb
|
112
|
+
- lib/f_http_client/processor/response.rb
|
113
|
+
- lib/f_http_client/rspec.rb
|
114
|
+
- lib/f_http_client/rspec/support.rb
|
115
|
+
- lib/f_http_client/rspec/support/helpers.rb
|
116
|
+
- lib/f_http_client/rspec/support/helpers/fake_response.rb
|
117
|
+
- lib/f_http_client/rspec/support/support.rb
|
118
|
+
- lib/f_http_client/service.rb
|
119
|
+
- lib/f_http_client/store.rb
|
120
|
+
- lib/f_http_client/version.rb
|
121
|
+
- sig/f_http_client.rbs
|
122
|
+
homepage: https://github.com/Fretadao/f_http_client
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata:
|
126
|
+
homepage_uri: https://github.com/Fretadao/f_http_client
|
127
|
+
source_code_uri: https://github.com/Fretadao/f_http_client
|
128
|
+
changelog_uri: https://github.com/Fretadao/f_http_client/blob/master/CHANGELOG.md
|
129
|
+
rubygems_mfa_required: 'true'
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 3.0.0
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubygems_version: 3.3.5
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: Gem to provade a base for an HTTP client using FService architecture
|
149
|
+
test_files: []
|