api_adaptor 0.0.1 → 0.0.2
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/.rubocop.yml +9 -0
- data/Gemfile.lock +28 -26
- data/README.md +30 -24
- data/lib/api_adaptor/base.rb +67 -63
- data/lib/api_adaptor/exceptions.rb +3 -1
- data/lib/api_adaptor/headers.rb +5 -3
- data/lib/api_adaptor/json_client.rb +24 -24
- data/lib/api_adaptor/list_response.rb +8 -12
- data/lib/api_adaptor/response.rb +7 -5
- data/lib/api_adaptor/variables.rb +14 -12
- data/lib/api_adaptor/version.rb +1 -1
- metadata +26 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d434d1287d28256b67543919c32dba816a5c6a682247108a985eee72ac7ca86c
|
|
4
|
+
data.tar.gz: e386558347941960b7c54bbd0107381202bfcf4c8318c0ac3908cf2bd3e1c99a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ee873a96fa726a95caf41861a683abc276571b3a6424ae44f7ede1c0cc27e242de879b7f8f73930f10c0347d60ff6d31595ba55235a5be1a39e36208359e524
|
|
7
|
+
data.tar.gz: 0a42e0ded563c8f1b9cab2433c8f3f5ca5160da8df923deb80382ecb3736012fa0a136d53799b4681011f6723c18eceaf5fd9e3e2ee853071ca4d38a9903b1ba
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,43 +1,47 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
api_adaptor (0.0.
|
|
4
|
+
api_adaptor (0.0.2)
|
|
5
5
|
addressable (~> 2.8)
|
|
6
|
+
link_header (~> 0.0.8)
|
|
6
7
|
rest-client (~> 2.1)
|
|
7
8
|
|
|
8
9
|
GEM
|
|
9
10
|
remote: https://rubygems.org/
|
|
10
11
|
specs:
|
|
11
|
-
addressable (2.8.
|
|
12
|
+
addressable (2.8.6)
|
|
12
13
|
public_suffix (>= 2.0.2, < 6.0)
|
|
13
14
|
ast (2.4.2)
|
|
14
15
|
crack (0.4.5)
|
|
15
16
|
rexml
|
|
16
17
|
diff-lcs (1.5.0)
|
|
17
|
-
domain_name (0.
|
|
18
|
-
|
|
19
|
-
hashdiff (1.0.1)
|
|
18
|
+
domain_name (0.6.20240107)
|
|
19
|
+
hashdiff (1.1.0)
|
|
20
20
|
http-accept (1.7.0)
|
|
21
21
|
http-cookie (1.0.5)
|
|
22
22
|
domain_name (~> 0.5)
|
|
23
|
-
json (2.
|
|
24
|
-
|
|
23
|
+
json (2.7.1)
|
|
24
|
+
language_server-protocol (3.17.0.3)
|
|
25
|
+
link_header (0.0.8)
|
|
26
|
+
mime-types (3.5.2)
|
|
25
27
|
mime-types-data (~> 3.2015)
|
|
26
|
-
mime-types-data (3.2023.
|
|
28
|
+
mime-types-data (3.2023.1205)
|
|
27
29
|
netrc (0.11.0)
|
|
28
|
-
parallel (1.
|
|
29
|
-
parser (3.
|
|
30
|
+
parallel (1.24.0)
|
|
31
|
+
parser (3.3.0.3)
|
|
30
32
|
ast (~> 2.4.1)
|
|
31
|
-
|
|
33
|
+
racc
|
|
34
|
+
public_suffix (5.0.4)
|
|
35
|
+
racc (1.7.3)
|
|
32
36
|
rainbow (3.1.1)
|
|
33
|
-
rake (13.0
|
|
34
|
-
regexp_parser (2.
|
|
37
|
+
rake (13.1.0)
|
|
38
|
+
regexp_parser (2.9.0)
|
|
35
39
|
rest-client (2.1.0)
|
|
36
40
|
http-accept (>= 1.7.0, < 2.0)
|
|
37
41
|
http-cookie (>= 1.0.2, < 2.0)
|
|
38
42
|
mime-types (>= 1.16, < 4.0)
|
|
39
43
|
netrc (~> 0.8)
|
|
40
|
-
rexml (3.2.
|
|
44
|
+
rexml (3.2.6)
|
|
41
45
|
rspec (3.12.0)
|
|
42
46
|
rspec-core (~> 3.12.0)
|
|
43
47
|
rspec-expectations (~> 3.12.0)
|
|
@@ -47,29 +51,27 @@ GEM
|
|
|
47
51
|
rspec-expectations (3.12.3)
|
|
48
52
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
49
53
|
rspec-support (~> 3.12.0)
|
|
50
|
-
rspec-mocks (3.12.
|
|
54
|
+
rspec-mocks (3.12.6)
|
|
51
55
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
52
56
|
rspec-support (~> 3.12.0)
|
|
53
|
-
rspec-support (3.12.
|
|
54
|
-
rubocop (1.
|
|
57
|
+
rspec-support (3.12.1)
|
|
58
|
+
rubocop (1.59.0)
|
|
55
59
|
json (~> 2.3)
|
|
60
|
+
language_server-protocol (>= 3.17.0)
|
|
56
61
|
parallel (~> 1.10)
|
|
57
|
-
parser (>= 3.2.
|
|
62
|
+
parser (>= 3.2.2.4)
|
|
58
63
|
rainbow (>= 2.2.2, < 4.0)
|
|
59
64
|
regexp_parser (>= 1.8, < 3.0)
|
|
60
65
|
rexml (>= 3.2.5, < 4.0)
|
|
61
|
-
rubocop-ast (>= 1.
|
|
66
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
|
62
67
|
ruby-progressbar (~> 1.7)
|
|
63
68
|
unicode-display_width (>= 2.4.0, < 3.0)
|
|
64
|
-
rubocop-ast (1.
|
|
69
|
+
rubocop-ast (1.30.0)
|
|
65
70
|
parser (>= 3.2.1.0)
|
|
66
71
|
ruby-progressbar (1.13.0)
|
|
67
|
-
timecop (0.9.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
unf_ext (0.0.8.2)
|
|
71
|
-
unicode-display_width (2.4.2)
|
|
72
|
-
webmock (3.18.1)
|
|
72
|
+
timecop (0.9.8)
|
|
73
|
+
unicode-display_width (2.5.0)
|
|
74
|
+
webmock (3.19.1)
|
|
73
75
|
addressable (>= 2.8.0)
|
|
74
76
|
crack (>= 0.3.2)
|
|
75
77
|
hashdiff (>= 0.4.0, < 2.0.0)
|
data/README.md
CHANGED
|
@@ -7,17 +7,21 @@ Intended to bootstrap the quick writing of Adaptors for specific APIs, without h
|
|
|
7
7
|
|
|
8
8
|
Install the gem and add to the application's Gemfile by executing:
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
```shell
|
|
11
|
+
bundle add api_adaptor
|
|
12
|
+
```
|
|
11
13
|
|
|
12
14
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
```shell
|
|
17
|
+
gem install api_adaptor
|
|
18
|
+
```
|
|
15
19
|
|
|
16
20
|
## Usage
|
|
17
21
|
|
|
18
22
|
Use the ApiAdaptor as a base class for your API wrapper, for example:
|
|
19
23
|
|
|
20
|
-
```
|
|
24
|
+
```ruby
|
|
21
25
|
class MyApi < ApiAdaptor::Base
|
|
22
26
|
def base_url
|
|
23
27
|
endpoint
|
|
@@ -29,46 +33,46 @@ Use your new class to create a client that can make HTTP requests to JSON APIs f
|
|
|
29
33
|
|
|
30
34
|
### GET JSON
|
|
31
35
|
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
```ruby
|
|
37
|
+
client = MyApi.new
|
|
38
|
+
response = client.get_json("http://some.endpoint/json")
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
### POST JSON
|
|
38
42
|
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
```ruby
|
|
44
|
+
client = MyApi.new
|
|
45
|
+
response = client.post_json("http://some.endpoint/json", { "foo": "bar" })
|
|
42
46
|
```
|
|
43
47
|
|
|
44
48
|
### PUT JSON
|
|
45
49
|
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
```ruby
|
|
51
|
+
client = MyApi.new
|
|
52
|
+
response = client.put_json("http://some.endpoint/json", { "foo": "bar" })
|
|
49
53
|
```
|
|
50
54
|
|
|
51
55
|
### PATCH JSON
|
|
52
56
|
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
```ruby
|
|
58
|
+
client = MyApi.new
|
|
59
|
+
response = client.patch_json("http://some.endpoint/json", { "foo": "bar" })
|
|
56
60
|
```
|
|
57
61
|
|
|
58
62
|
### DELETE JSON
|
|
59
63
|
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
```ruby
|
|
65
|
+
client = MyApi.new
|
|
66
|
+
response = client.delete_json("http://some.endpoint/json", { "foo": "bar" })
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
### GET raw requests
|
|
66
70
|
|
|
67
71
|
you can also get a raw response from the API
|
|
68
72
|
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
```ruby
|
|
74
|
+
client = MyApi.new
|
|
75
|
+
response = client.get_raw("http://some.endpoint/json")
|
|
72
76
|
```
|
|
73
77
|
|
|
74
78
|
## Environment variables
|
|
@@ -77,20 +81,22 @@ User Agent is populated with a default string.
|
|
|
77
81
|
See .env.example.
|
|
78
82
|
|
|
79
83
|
For instance if you provide:
|
|
80
|
-
|
|
84
|
+
|
|
85
|
+
```bash
|
|
81
86
|
APP_NAME=test_app
|
|
82
87
|
APP_VERSION=1.0.0
|
|
83
88
|
APP_CONTACT=contact@example.com
|
|
84
89
|
```
|
|
85
90
|
|
|
86
91
|
User agent would read
|
|
87
|
-
|
|
92
|
+
|
|
93
|
+
```text
|
|
88
94
|
test_app/1.0.0 (contact@example.com)
|
|
89
95
|
```
|
|
90
96
|
|
|
91
97
|
## Contributing
|
|
92
98
|
|
|
93
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/huwd/api_adaptor
|
|
99
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/huwd/api_adaptor>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/huwd/api_adaptor/blob/main/CODE_OF_CONDUCT.md).
|
|
94
100
|
|
|
95
101
|
## License
|
|
96
102
|
|
data/lib/api_adaptor/base.rb
CHANGED
|
@@ -1,86 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative "json_client"
|
|
2
4
|
require "cgi"
|
|
3
5
|
require_relative "null_logger"
|
|
4
6
|
require_relative "list_response"
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
class
|
|
8
|
-
|
|
8
|
+
module ApiAdaptor
|
|
9
|
+
class Base
|
|
10
|
+
class InvalidAPIURL < StandardError
|
|
11
|
+
end
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
extend Forwardable
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
def client
|
|
16
|
+
@client ||= create_client
|
|
17
|
+
end
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
def create_client
|
|
20
|
+
ApiAdaptor::JsonClient.new(options)
|
|
21
|
+
end
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
def_delegators :client,
|
|
24
|
+
:get_json,
|
|
25
|
+
:post_json,
|
|
26
|
+
:put_json,
|
|
27
|
+
:patch_json,
|
|
28
|
+
:delete_json,
|
|
29
|
+
:get_raw,
|
|
30
|
+
:get_raw!,
|
|
31
|
+
:put_multipart,
|
|
32
|
+
:post_multipart
|
|
33
|
+
|
|
34
|
+
attr_reader :options
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
attr_writer :logger
|
|
38
|
+
attr_accessor :default_options
|
|
39
|
+
end
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
def self.logger
|
|
42
|
+
@logger ||= ApiAdaptor::NullLogger.new
|
|
43
|
+
end
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
def initialize(endpoint_url, options = {})
|
|
46
|
+
options[:endpoint_url] = endpoint_url
|
|
47
|
+
raise InvalidAPIURL unless endpoint_url =~ URI::RFC3986_Parser::RFC3986_URI
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
base_options = { logger: ApiAdaptor::Base.logger }
|
|
50
|
+
default_options = base_options.merge(ApiAdaptor::Base.default_options || {})
|
|
51
|
+
@options = default_options.merge(options)
|
|
52
|
+
self.endpoint = options[:endpoint_url]
|
|
53
|
+
end
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
def url_for_slug(slug, options = {})
|
|
56
|
+
"#{base_url}/#{slug}.json#{query_string(options)}"
|
|
57
|
+
end
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
def get_list(url)
|
|
60
|
+
get_json(url) do |r|
|
|
61
|
+
ApiAdaptor::ListResponse.new(r, self)
|
|
62
|
+
end
|
|
59
63
|
end
|
|
60
|
-
end
|
|
61
64
|
|
|
62
|
-
private
|
|
65
|
+
private
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
attr_accessor :endpoint
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
def query_string(params)
|
|
70
|
+
return "" if params.empty?
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
param_pairs = params.sort.map do |key, value|
|
|
73
|
+
case value
|
|
74
|
+
when Array
|
|
75
|
+
value.map do |v|
|
|
76
|
+
"#{CGI.escape("#{key}[]")}=#{CGI.escape(v.to_s)}"
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
|
|
74
80
|
end
|
|
75
|
-
|
|
76
|
-
"#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
|
|
77
|
-
end
|
|
78
|
-
}.flatten
|
|
81
|
+
end.flatten
|
|
79
82
|
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
"?#{param_pairs.join("&")}"
|
|
84
|
+
end
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
def uri_encode(param)
|
|
87
|
+
Addressable::URI.encode(param.to_s)
|
|
88
|
+
end
|
|
85
89
|
end
|
|
86
|
-
end
|
|
90
|
+
end
|
data/lib/api_adaptor/headers.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ApiAdaptor
|
|
2
4
|
class Headers
|
|
3
5
|
class << self
|
|
@@ -6,18 +8,18 @@ module ApiAdaptor
|
|
|
6
8
|
end
|
|
7
9
|
|
|
8
10
|
def headers
|
|
9
|
-
header_data.reject { |_k, v|
|
|
11
|
+
header_data.reject { |_k, v| v.nil? || v.empty? }
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def clear_headers
|
|
13
15
|
Thread.current[:headers] = {}
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
private
|
|
17
19
|
|
|
18
20
|
def header_data
|
|
19
21
|
Thread.current[:headers] ||= {}
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
|
-
end
|
|
25
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative "exceptions"
|
|
2
4
|
require_relative "variables"
|
|
3
5
|
require_relative "null_logger"
|
|
@@ -13,9 +15,7 @@ module ApiAdaptor
|
|
|
13
15
|
attr_accessor :logger, :options
|
|
14
16
|
|
|
15
17
|
def initialize(options = {})
|
|
16
|
-
if options[:disable_timeout] || options[:timeout].to_i.negative?
|
|
17
|
-
raise "It is no longer possible to disable the timeout."
|
|
18
|
-
end
|
|
18
|
+
raise "It is no longer possible to disable the timeout." if options[:disable_timeout] || options[:timeout].to_i.negative?
|
|
19
19
|
|
|
20
20
|
@logger = options[:logger] || NullLogger.new
|
|
21
21
|
@options = options
|
|
@@ -24,7 +24,7 @@ module ApiAdaptor
|
|
|
24
24
|
def self.default_request_headers
|
|
25
25
|
{
|
|
26
26
|
"Accept" => "application/json",
|
|
27
|
-
"User-Agent" => "#{Variables.app_name}/#{Variables.app_version} (#{Variables.
|
|
27
|
+
"User-Agent" => "#{Variables.app_name}/#{Variables.app_version} (#{Variables.app_contact})"
|
|
28
28
|
}
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -34,7 +34,7 @@ module ApiAdaptor
|
|
|
34
34
|
|
|
35
35
|
def self.json_body_headers
|
|
36
36
|
{
|
|
37
|
-
"Content-Type" => "application/json"
|
|
37
|
+
"Content-Type" => "application/json"
|
|
38
38
|
}
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -78,7 +78,7 @@ module ApiAdaptor
|
|
|
78
78
|
Response.new(r)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
private
|
|
82
82
|
|
|
83
83
|
def do_raw_request(method, url, params = nil)
|
|
84
84
|
do_request(method, url, params)
|
|
@@ -94,9 +94,7 @@ module ApiAdaptor
|
|
|
94
94
|
# from the Net::HTTPResponse
|
|
95
95
|
def do_json_request(method, url, params = nil, additional_headers = {}, &create_response)
|
|
96
96
|
begin
|
|
97
|
-
if params
|
|
98
|
-
additional_headers.merge!(self.class.json_body_headers)
|
|
99
|
-
end
|
|
97
|
+
additional_headers.merge!(self.class.json_body_headers) if params
|
|
100
98
|
response = do_request(method, url, (params.to_json if params), additional_headers)
|
|
101
99
|
rescue RestClient::Exception => e
|
|
102
100
|
# Attempt to parse the body as JSON if possible
|
|
@@ -119,25 +117,24 @@ module ApiAdaptor
|
|
|
119
117
|
if @options[:bearer_token]
|
|
120
118
|
headers = method_params[:headers] || {}
|
|
121
119
|
method_params.merge(headers: headers.merge(
|
|
122
|
-
"Authorization" => "Bearer #{@options[:bearer_token]}"
|
|
120
|
+
"Authorization" => "Bearer #{@options[:bearer_token]}"
|
|
123
121
|
))
|
|
124
122
|
elsif @options[:basic_auth]
|
|
125
123
|
method_params.merge(
|
|
126
124
|
user: @options[:basic_auth][:user],
|
|
127
|
-
password: @options[:basic_auth][:password]
|
|
125
|
+
password: @options[:basic_auth][:password]
|
|
128
126
|
)
|
|
129
127
|
else
|
|
130
128
|
method_params
|
|
131
129
|
end
|
|
132
130
|
end
|
|
133
131
|
|
|
134
|
-
|
|
135
132
|
# Take a hash of parameters for Request#execute; return a hash of
|
|
136
133
|
# parameters with timeouts included
|
|
137
134
|
def with_timeout(method_params)
|
|
138
135
|
method_params.merge(
|
|
139
136
|
timeout: options[:timeout] || DEFAULT_TIMEOUT_IN_SECONDS,
|
|
140
|
-
open_timeout: options[:timeout] || DEFAULT_TIMEOUT_IN_SECONDS
|
|
137
|
+
open_timeout: options[:timeout] || DEFAULT_TIMEOUT_IN_SECONDS
|
|
141
138
|
)
|
|
142
139
|
end
|
|
143
140
|
|
|
@@ -146,14 +143,14 @@ module ApiAdaptor
|
|
|
146
143
|
headers: default_headers
|
|
147
144
|
.merge(method_params[:headers] || {})
|
|
148
145
|
.merge(ApiAdaptor::Headers.headers)
|
|
149
|
-
.merge(additional_headers)
|
|
146
|
+
.merge(additional_headers)
|
|
150
147
|
)
|
|
151
148
|
end
|
|
152
149
|
|
|
153
150
|
def with_ssl_options(method_params)
|
|
154
151
|
method_params.merge(
|
|
155
152
|
# This is the default value anyway, but we should probably be explicit
|
|
156
|
-
verify_ssl: OpenSSL::SSL::VERIFY_NONE
|
|
153
|
+
verify_ssl: OpenSSL::SSL::VERIFY_NONE
|
|
157
154
|
)
|
|
158
155
|
end
|
|
159
156
|
|
|
@@ -164,26 +161,27 @@ module ApiAdaptor
|
|
|
164
161
|
|
|
165
162
|
method_params = {
|
|
166
163
|
method: method,
|
|
167
|
-
url: url
|
|
164
|
+
url: url
|
|
168
165
|
}
|
|
169
166
|
|
|
170
167
|
method_params[:payload] = params
|
|
171
168
|
method_params = with_timeout(method_params)
|
|
172
169
|
method_params = with_headers(method_params, self.class.default_request_headers, additional_headers)
|
|
173
170
|
method_params = with_auth_options(method_params)
|
|
174
|
-
if URI.parse(url).is_a? URI::HTTPS
|
|
175
|
-
method_params = with_ssl_options(method_params)
|
|
176
|
-
end
|
|
171
|
+
method_params = with_ssl_options(method_params) if URI.parse(url).is_a? URI::HTTPS
|
|
177
172
|
|
|
178
173
|
::RestClient::Request.execute(method_params)
|
|
179
174
|
rescue Errno::ECONNREFUSED => e
|
|
180
|
-
logger.error loggable.merge(status: "refused", error_message: e.message, error_class: e.class.name,
|
|
175
|
+
logger.error loggable.merge(status: "refused", error_message: e.message, error_class: e.class.name,
|
|
176
|
+
end_time: Time.now.to_f).to_json
|
|
181
177
|
raise ApiAdaptor::EndpointNotFound, "Could not connect to #{url}"
|
|
182
178
|
rescue RestClient::Exceptions::Timeout => e
|
|
183
|
-
logger.error loggable.merge(status: "timeout", error_message: e.message, error_class: e.class.name,
|
|
179
|
+
logger.error loggable.merge(status: "timeout", error_message: e.message, error_class: e.class.name,
|
|
180
|
+
end_time: Time.now.to_f).to_json
|
|
184
181
|
raise ApiAdaptor::TimedOutException, e.message
|
|
185
182
|
rescue URI::InvalidURIError => e
|
|
186
|
-
logger.error loggable.merge(status: "invalid_uri", error_message: e.message, error_class: e.class.name,
|
|
183
|
+
logger.error loggable.merge(status: "invalid_uri", error_message: e.message, error_class: e.class.name,
|
|
184
|
+
end_time: Time.now.to_f).to_json
|
|
187
185
|
raise ApiAdaptor::InvalidUrl, e.message
|
|
188
186
|
rescue RestClient::Exception => e
|
|
189
187
|
# Log the error here, since we have access to loggable, but raise the
|
|
@@ -192,10 +190,12 @@ module ApiAdaptor
|
|
|
192
190
|
logger.warn loggable.to_json
|
|
193
191
|
raise
|
|
194
192
|
rescue Errno::ECONNRESET => e
|
|
195
|
-
logger.error loggable.merge(status: "connection_reset", error_message: e.message, error_class: e.class.name,
|
|
193
|
+
logger.error loggable.merge(status: "connection_reset", error_message: e.message, error_class: e.class.name,
|
|
194
|
+
end_time: Time.now.to_f).to_json
|
|
196
195
|
raise ApiAdaptor::TimedOutException, e.message
|
|
197
196
|
rescue SocketError => e
|
|
198
|
-
logger.error loggable.merge(status: "socket_error", error_message: e.message, error_class: e.class.name,
|
|
197
|
+
logger.error loggable.merge(status: "socket_error", error_message: e.message, error_class: e.class.name,
|
|
198
|
+
end_time: Time.now.to_f).to_json
|
|
199
199
|
raise ApiAdaptor::SocketErrorException, e.message
|
|
200
200
|
end
|
|
201
201
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "json"
|
|
2
4
|
require "api_adaptor/response"
|
|
3
5
|
require "link_header"
|
|
@@ -24,7 +26,7 @@ module ApiAdaptor
|
|
|
24
26
|
to_hash["results"]
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
def
|
|
29
|
+
def next_page?
|
|
28
30
|
!page_link("next").nil?
|
|
29
31
|
end
|
|
30
32
|
|
|
@@ -33,20 +35,16 @@ module ApiAdaptor
|
|
|
33
35
|
# avoid us making multiple requests for the same page, but we shouldn't
|
|
34
36
|
# allow the data to change once it's already been loaded, so long as we
|
|
35
37
|
# retain a reference to any one page in the sequence
|
|
36
|
-
@next_page ||= if
|
|
37
|
-
@api_client.get_list page_link("next").href
|
|
38
|
-
end
|
|
38
|
+
@next_page ||= (@api_client.get_list page_link("next").href if next_page?)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def
|
|
41
|
+
def previous_page?
|
|
42
42
|
!page_link("previous").nil?
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def previous_page
|
|
46
46
|
# See the note in `next_page` for why this is memoised
|
|
47
|
-
@previous_page ||= if
|
|
48
|
-
@api_client.get_list(page_link("previous").href)
|
|
49
|
-
end
|
|
47
|
+
@previous_page ||= (@api_client.get_list(page_link("previous").href) if previous_page?)
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
# Transparently get all results across all pages. Compare this with #each
|
|
@@ -70,13 +68,11 @@ module ApiAdaptor
|
|
|
70
68
|
def with_subsequent_pages
|
|
71
69
|
Enumerator.new do |yielder|
|
|
72
70
|
each { |i| yielder << i }
|
|
73
|
-
if
|
|
74
|
-
next_page.with_subsequent_pages.each { |i| yielder << i }
|
|
75
|
-
end
|
|
71
|
+
next_page.with_subsequent_pages.each { |i| yielder << i } if next_page?
|
|
76
72
|
end
|
|
77
73
|
end
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
private
|
|
80
76
|
|
|
81
77
|
def link_header
|
|
82
78
|
@link_header ||= LinkHeader.parse @http_response.headers[:link]
|
data/lib/api_adaptor/response.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "json"
|
|
2
4
|
require "forwardable"
|
|
3
5
|
|
|
@@ -20,7 +22,7 @@ module ApiAdaptor
|
|
|
20
22
|
include Enumerable
|
|
21
23
|
|
|
22
24
|
class CacheControl < Hash
|
|
23
|
-
PATTERN = /([-a-z]+)(?:\s*=\s*([^,\s]+))?,?+/i
|
|
25
|
+
PATTERN = /([-a-z]+)(?:\s*=\s*([^,\s]+))?,?+/i.freeze
|
|
24
26
|
|
|
25
27
|
def initialize(value = nil)
|
|
26
28
|
super()
|
|
@@ -58,12 +60,12 @@ module ApiAdaptor
|
|
|
58
60
|
def reverse_max_age
|
|
59
61
|
self["r-maxage"].to_i if key?("r-maxage")
|
|
60
62
|
end
|
|
61
|
-
|
|
63
|
+
alias r_maxage reverse_max_age
|
|
62
64
|
|
|
63
65
|
def shared_max_age
|
|
64
66
|
self["s-maxage"].to_i if key?("r-maxage")
|
|
65
67
|
end
|
|
66
|
-
|
|
68
|
+
alias s_maxage shared_max_age
|
|
67
69
|
|
|
68
70
|
def to_s
|
|
69
71
|
directives = []
|
|
@@ -152,7 +154,7 @@ module ApiAdaptor
|
|
|
152
154
|
false
|
|
153
155
|
end
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
private
|
|
156
158
|
|
|
157
159
|
def transform_parsed(value)
|
|
158
160
|
return value if @web_urls_relative_to.nil?
|
|
@@ -180,4 +182,4 @@ module ApiAdaptor
|
|
|
180
182
|
end
|
|
181
183
|
end
|
|
182
184
|
end
|
|
183
|
-
end
|
|
185
|
+
end
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
module Variables
|
|
3
|
-
def self.app_name
|
|
4
|
-
ENV['APP_NAME'] || "Ruby ApiAdaptor App"
|
|
5
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
module ApiAdaptor
|
|
4
|
+
module Variables
|
|
5
|
+
def self.app_name
|
|
6
|
+
ENV["APP_NAME"] || "Ruby ApiAdaptor App"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.app_version
|
|
10
|
+
ENV["APP_VERSION"] || "Version not stated"
|
|
11
|
+
end
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
13
|
+
def self.app_contact
|
|
14
|
+
ENV["APP_CONTACT"] || "Contact not stated"
|
|
14
15
|
end
|
|
15
|
-
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/api_adaptor/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: api_adaptor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Huw Diprose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-01-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: addressable
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.
|
|
19
|
+
version: '2.8'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '2.
|
|
26
|
+
version: '2.8'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: link_header
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 0.0.8
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 0.0.8
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: rest-client
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: '2.1'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: '2.1'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: rake
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '13.0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '13.0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: rspec
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0
|
|
75
|
+
version: '3.0'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0
|
|
82
|
+
version: '3.0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: rubocop
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
89
|
+
version: '1.21'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
96
|
+
version: '1.21'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: timecop
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
101
|
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
103
|
+
version: '0.9'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
108
|
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
110
|
+
version: '0.9'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
112
|
+
name: webmock
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
|
115
115
|
- - "~>"
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '
|
|
117
|
+
version: '3.18'
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '
|
|
124
|
+
version: '3.18'
|
|
125
125
|
description: A basic adaptor to send HTTP requests and parse the responses. Intended
|
|
126
126
|
to bootstrap the quick writing of Adaptors for specific APIs, without having to
|
|
127
127
|
write the same old JSON request and processing time and time again.
|